web-dev-qa-db-fra.com

Angular 4 setTimeout n'attend pas

Je crée une angular 4 avec TypeScript.

J'ai une fonction qui doit être exécutée toutes les 10 secondes jusqu'à une condition d'arrêt spécifiée. J'ai créé une boucle avec un testcode en utilisant setTimeout pour voir si cela fonctionnerait.

Mon code de test:

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

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

Cependant, cela semble attendre 3 secondes, ou le navigateur est tout simplement lent ... et ensuite, il imprime 4 fois. Donc, le code ne fonctionne pas. Est-ce que je fais mal ou y a-t-il d'autres possibilités de faire ce genre de choses?

18
fangio

Puisque vous utilisez Angular, vous pouvez probablement le faire d’une manière beaucoup plus simple en utilisant takeWhile :

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

Oui, vous vous trompez: vous avez une boucle qui indique 4 fois de suite à exécuter timer() 3 secondes plus tard, à partir de maintenant.

Pour faire ce que vous voulez, vous devez reprogrammer le minuteur suivant à chaque fois que timer() est appelé ou, plus simplement, pour utiliser setInterval() :

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

Notez que, puisque vous utilisez angular, utiliser des observables serait beaucoup plus simple:

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

Je l'ai fait avec angulaire 6. Ce code demande toutes les 5 secondes pour obtenir l'avancement du rendu. Il cesse d’envoyer la demande lorsque la progression atteint 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
Günay Gültekin

Ce n'est en effet pas le moyen d'utiliser une méthode async. La boucle while passe simplement 4 fois en une fois et lance les 4 minuteries. Ce qui sortira simultanément en 3 secondes. Vous pouvez cependant utiliser les fonctionnalités await et async de TypeScript:

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;
    }
}

Ceci lancera la méthode execute toutes les 10 secondes, aussi longtemps que le stopCondition === false. Quand le stopCondition === true _ il sortira done.

3
PierreDuc

Utilisez la fonction setInterval(hander:(args:any[]),ms:Number,args:any[]), qui est l’une des méthodes de OnInit.

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

Affichera l'alerte "oui" après 10 secondes.

2
srlgrg

Puisque vous appelez setTimeout dans une boucle while et que l'exécution d'instructions est asynchrone, il n'attendra pas l'exécution de la fonction Timer avant de passer à la prochaine itération. Vous pouvez obtenir les fonctionnalités requises en utilisant le code ci-dessous

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

Oui, c'est un comportement correct. Vous avez une boucle synchrone qui a créé 4 actions retardées et termine cette boucle. Cela se produit en quelques millisecondes. Ainsi, les 4 actions différées sont enregistrées pour être démarrées en 3 secondes, à peu près au même moment.

Donc, en 3 secondes, vous recevrez toutes les 4 réponses de cette action différée.

Si vous souhaitez que l'exécution de l'appel soit consécutive (première après 3 secondes, seconde après première), envisagez d'utiliser les promesses pour cela et appelez la nouvelle promesse avec un délai de 3 secondes après l'achèvement précédent.

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

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

0
VadimB