【问题标题】:Angular 4 setTimeout does not waitAngular 4 setTimeout 不等待
【发布时间】:2017-12-16 20:35:26
【问题描述】:

我正在使用 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次完成。所以代码不起作用。我做错了还是有其他可能做这种事情?

【问题讨论】:

    标签: angular typescript settimeout


    【解决方案1】:

    由于您使用的是 Angular,因此您可以使用takeWhile 以更简单的方式执行此操作:

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

    【讨论】:

    • 当我尝试这个时,我得到一个错误:ERROR TypeError: WEBPACK_IMPORTED_MODULE_3_rxjs_Observable.Observable.interval is not a function
    • 这太荒谬了,我从 rxjs/Observable 导入了 { Observable },但不起作用...谢谢您的回答 :)
    • @fangio 永远不要导入from "rxjs"。这将导入所有 Observable 静态方法和运算符,这将使您的应用程序包比应有的更大。使用您的导入,并添加import 'rxjs/add/observable/interval'; import 'rxjs/add/operator/takeWhile';`。这只会导入您实际使用的方法和运算符。
    【解决方案2】:

    是的,你做错了:你有一个循环告诉连续 4 次在 3 秒后执行 timer(),从现在开始。

    要做你想做的事,你必须在每次调用timer() 时重新安排下一个计时器,或者更简单地说,使用setInterval():

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

    请注意,由于您使用的是 angular,因此使用 observables 会更容易:

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

    【讨论】:

    • 仅供我自己参考,如果满足某个条件,如何使Observable间隔停止。例如当一个类字段变为true
    • takeWhile(() =&gt; !this.someField)
    • 可爱!好像他们对所有事情都有解决方案:)
    • @JBNizet 你能说明如何正确导入库吗?
    【解决方案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 秒内同时输出。但是,您可以利用 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;
          }
      }
      

      这将在每 10 秒后运行 execute 方法,持续时间与 stopCondition === false 一样长。当stopCondition === true 将输出done。

      【讨论】:

      • 这对我有用。我不得不删除“void”,因为异步函数不支持 ES5。但上述方法奏效了。感谢您抽出宝贵时间为此做出贡献。
      • @Kirk 我确实很糟糕。 typescript 应该是Promise&lt;void&gt;,而且 ES5 不支持打字,所以你应该删除它:)
      【解决方案5】:

      使用函数setInterval(hander:(args:any[]),ms:Number,args:any[]),它是OnInit的方法之一。

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

      将在 10 秒后显示“是”警报。

      【讨论】:

      • 您是否在切换布尔属性的角度函数中尝试过这个?似乎对我的不起作用...
      【解决方案6】:

      是的,这是正确的行为。您有创建 4 个延迟动作并结束此循环的同步循环。它发生在几毫秒内。所以所有 4 个延迟的动作都被注册为在 3 秒内开始,大约在同一时间。

      因此,您将在 3 秒内收到来自此延迟操作的所有 4 个响应。

      如果您想要执行结果调用(第一次在 3 秒后,然后在第一次之后),请考虑为此使用 Promise 并在上一次完成后延迟 3 秒调用新的 Promise。

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

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

      【讨论】:

        【解决方案7】:

        由于您在 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")
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-01-22
          • 1970-01-01
          • 2019-10-16
          • 1970-01-01
          • 2019-01-20
          • 1970-01-01
          • 1970-01-01
          • 2011-07-03
          相关资源
          最近更新 更多