为什么setTimeout()会使我的应用程序变慢,而Rxjs timer()。subscribe(…)却没有?


9

我有一个组件,它以100毫秒的间隔“延迟加载”一些注释。

当我使用setTimeout时,它确实很慢。

零件

<div *ngFor="let post of posts">
   <app-post [post]="post" ></app-post>
</div>

这使我的应用程序延迟(平均fps 14,空闲时间51100ms):

while(this.postService.hasPosts()){
  setTimeout(()=> {
   this.posts.push(this.postService.next(10));
  },100);
}

这使我的应用程序流畅(平均fps 35,空闲时间40800ms)

while(this.postService.hasPosts()){
  timer(100).subscribe(()=> {
    this.posts.push(this.postService.next(10));
  });
}

有什么解释,为什么rxjs计时器能更好地工作?

我使用firefox进行了运行时分析。在第一个示例中,帧速率降至14 fps;在另一个示例中,帧速率降至35 fps。

甚至空闲时间也减少了20%。

此方法更加平滑(平均fps 45,空闲时间13500ms):

interval(100).pipe(takeWhile(this.postService.hasPosts()).subscribe(()=> {
    this.posts.push(this.postService.next(10));
  });
}

Answers:


2

您最后的解决方案是唯一正确的解决方案。

其他两个解决方案不应像您期望的那样工作。实际上,这将导致无限循环。

这是因为JavaScript的eventloop如何工作。下图显示了JavaScript运行时的模型(图像从此处获取):

在此处输入图片说明

对我们来说,相关的部分是stackqueue。JavaScript运行时处理上的消息queue。每个消息都与一个函数关联,该函数在处理消息时会被调用。

对于堆栈,每个函数调用都会在堆栈上创建一个框架,其中包含函数参数和局部变量。如果一个函数调用另一个函数,则将新的框架压入堆栈的顶部。当函数返回时,顶部框架从堆栈中弹出。

现在,如果堆栈为空,则JavaScript运行时将处理queue(最早的)消息上的下一条消息。

如果使用setTimeout(() => doSomething(),100),则该doSomething()函数会在100毫秒后添加到队列中。这就是为什么100毫秒不是保证时间而是最短时间的原因。因此doSomething method,如果堆栈为空且队列中没有其他内容,则只会调用您的设备。

但是,当您在while循环中进行迭代并且条件取决于您内部的代码时setTimeout,您创建了一个无限循环,因为堆栈不会为空,因此您的this.posts.push(this.postService.next(10));代码将永远不会被调用。

对于RxJS实现,也是如此。他们使用调度程序来处理时间。有在RxJS不同的内部调度的实现,但我们可以在为实现中可以看到intervaltimer,如果我们不指定一个调度程序默认的是asyncScheduler。所述asyncScheduler调度工作与setInterval该工作方式类似于setTimeout上面提到的,并且在队列推动另一消息。

我用while循环尝试了两种解决方案,实际上第一种完全冻结了我的浏览器,而第二种则太慢了,但是可以在while循环内向控制台输出一些信息。我实际上不知道为什么第二个要好一些,但是尽管如此,两者都不是您真正想要的。您已经想出了一个好的解决方案,希望此答案可以帮助您理解为什么第一个解决方案的效果如此差。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.