Angular 4 setTimeout не ждет

Я создаю приложение angular 4 с typescript.

У меня есть функция, которая должна выполняться каждые 10 секунд до указанного условия остановки. Я создал цикл с некоторым тестовым кодом, используя setTimeout, чтобы узнать, будет ли он работать.

Мой тестовый код:

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

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

Однако это, кажется, ждет 3 секунды, или браузер просто медленный... а затем распечатывается 4 раза. Таким образом, код не работает. Я делаю это неправильно или есть другие возможности делать такие вещи?

Ответ 1

Поскольку вы используете Angular, вы можете сделать это гораздо проще, используя takeWhile:

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

Ответ 2

Да, вы делаете это неправильно: у вас есть цикл, говорящий 4 раза подряд, чтобы выполнить timer() через 3 секунды, начиная с этого момента.

Чтобы делать то, что вы хотите, вам придется перепланировать следующий таймер каждый раз, когда вызывается timer(), или, проще, использовать setInterval():

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

Обратите внимание, что поскольку вы используете angular, использование наблюдаемых будет намного проще:

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

Ответ 3

Я сделал это с 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
        }
      );
  });
}

Ответ 4

Это действительно не способ использовать метод async. Цикл while проходит 4 раза за один раз и запускает 4 таймера. Который будет выводить одновременно и через 3 секунды. Однако вы можете использовать функциональность await и async из 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;
    }
}

Это будет запускать метод execute через каждые 10 секунд, пока stopCondition === false. Когда stopCondition === true будет выводить done.

Ответ 5

Используйте функцию setInterval(hander:(args:any[]),ms:Number,args:any[]), которая является одним из методов OnInit.

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

Появится предупреждение "да" через 10 секунд.

Ответ 6

Да, это правильное поведение. У вас синхронный цикл, который создал 4 задержанных действия и завершает этот цикл. Это происходит за несколько миллисекунд. Таким образом, все 4 задержанных действия регистрируются для запуска через 3 секунды примерно в то же время.

Итак, через 3 секунды вы получите все 4 ответа от этих отложенных действий.

Если вы хотите иметь выполнение вызова последствий (сначала через 3 секунды, затем второй после первого), рассмотрите возможность использования promises для этого и вызовите новое обещание с 3-секундной задержкой после предыдущего завершения.

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

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

Ответ 7

Поскольку вы вызываете setTimeout внутри цикла while, и из-за асинхронного выполнения операторов он не будет ждать выполнения функции Timer перед тем, как перейти к следующей итерации. Вы можете достичь требуемой функциональности, используя приведенный ниже код

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

}

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