web-dev-qa-db-ja.com

Angular 4 setTimeoutは待機しません

TypeScriptでangular 4アプリを作成しています。

指定した停止条件まで10秒ごとに実行する必要がある関数があります。 setTimeoutを使用してテストコードでループを作成し、動作するかどうかを確認しました。

私のテストコード:

public run() {
    let i = 0;
    while (i < 4) {
        setTimeout(this.timer,3000);
        i++;
    }
}

public timer(){
    console.log("done")
}

ただし、これは3秒間待機するように見えます。または、ブラウザが遅いだけです...そして、4回印刷されます。そのため、コードは機能していません。私はこれを間違っていますか、この種のことを行う他の可能性がありますか?

18
fangio

Angularを使用しているため、おそらく takeWhile を使用して、これをはるかに簡単な方法で実行できます。

Observable.interval(10000)
    .takeWhile(() => !stopCondition)
    .subscribe(i => { 
        // This will be called every 10 seconds until `stopCondition` flag is set to true
    })
30
Saravana

はい、間違っています:3秒後にtimer()を実行するように連続して4回繰り返すループがあります。

必要なことを行うには、timer()が呼び出されるたびに次のタイマーを再スケジュールするか、より単純に setInterval() を使用する必要があります。

let count = 0;
const interval = window.setInterval(() => {
    this.timer();
    count++;
    if (count >= 4) {
        window.clearInterval(interval);
    }
}, 3000); 

角度を使用しているため、オブザーバブルを使用する方がはるかに簡単です。

Observable.interval(3000).take(4).subscribe(() => this.timer());
5
JB Nizet

Angular 6でやった。このコードは、レンダリングの進行状況を取得するために5秒ごとに要求します。進行状況が%100に達すると、要求の送信を停止します。

import {interval} from "rxjs";

getProgress(searchId): void{
const subscription = interval(5000)
  .subscribe(()=>{
    //Get progress status from the service every 5 seconds
    this.appService.getProgressStatus(searchId)
      .subscribe((jsonResult:any)=>{
          //update the progress on UI 

          //cancel subscribe until it reaches %100
          if(progressPercentage === 100)
            subscription.unsubscribe();
        },
        error => {
          //show errors
        }
      );
  });
}
5

これは実際、asyncメソッドを使用する方法ではありません。 whileループは、一度に4回だけループし、4つのタイマーを開始します。 3秒以内に同時に出力されます。ただし、TypeScriptのawaitおよびasync機能を活用できます。

public stopCondition: boolean = false;

public async run(): Promise<void> {
    while (!this.stopCondition) {
       await new Promise<void>(resolve => {
           setTimeout(resolve, 10000);
       });
       this.execute();
    }
    console.log('done');
}

public execute(): void {
    if ('whatever should trigger your stop condition') {
       this.stopCondition = true;
    }
}

これは、stopCondition === falseの間、10秒ごとにexecuteメソッドを実行します。 stopCondition === trueは、doneを出力します。

3
PierreDuc

OnInitのメソッドの1つである関数setInterval(hander:(args:any[]),ms:Number,args:any[])を使用します。

setInterval(a=>{
  alert("yes....");
},10000,[]);

10秒後にアラート「はい」が表示されます。

2
srlgrg

Whileループ内でsetTimeoutを呼び出しているため、ステートメントの非同期実行のため、次の反復に進む前にTimer関数の実行を待機しません。以下のコードを使用して必要な機能を実現できます

public run() {
    var i = 0;
    var interval = setInterval(() => {
        if (++i === 4) {                
            clearInterval(interval);
        }
        else {
            this.timer();
        }
    }, 3000);

}

public timer() {
    console.log("done")
}
0
Prathmesh Dali

はい、それは正しい動作です。 4つの遅延アクションを作成し、このループを終了する同期ループがあります。それは数ミリ秒で起こります。したがって、4つの遅延アクションはすべて、ほぼ同時に3秒で開始されるように登録されます。

したがって、3秒で、この遅延アクションから4つの応答すべてを受け取ることになります。

結果呼び出しの実行(最初は3秒後、2番目は最初)を行うには、これにpromiseを使用し、前の完了から3秒遅れて新しいpromiseを呼び出すことを検討してください。

fisrtPromise
   .then(secondPromise)
   .then(thirdPromise);

https://developer.mozilla.org/uk/docs/Web/JavaScript/Reference/Global_Objects/Promise

0
VadimB