有没有任何情况下,setTimeout(..,0)比requestAnimationFrame()更好?

14
我一直在使用 setTimeout(function(){ ... }, 0) 延迟一个函数的调用,让它在下一个事件周期执行。
通常我使用这种方法是为了直接操纵事件循环,确保按照特定顺序执行,大多数情况与 UI 有关。
有时我能感觉到 "tick",特别是当我将其用于在元素上运行某些第三方 JS 库时。
但最近我发现了 requestAnimationFrame。这基本上以更优雅的方式实现了相同的效果。
现在我很好奇,是否有任何情况下使用 setTimeout(function(){ ... }, 0)requestAnimationFrame(function(){ ... }) 更有利?

什么是“tick”?你会想到什么样的应用程序? - Bergi
显然它们在做不同的事情,所以你应该根据各自的目的使用它们? - Bergi
1
@Bergi:为什么这很明显?两者都表示“尽快完成”。 - wortwart
@wortwart 不,requestAnimationFrame 明确表示“在您认为重新渲染/重绘屏幕会很好时执行它”。 - Bergi
3个回答

5

它们不是同一件事。

使用setTimeout(fn, 0)调用自身的函数将尽可能频繁地运行。

使用requestAnimationFrame(fn)调用自身的函数将每帧调用一次 - 通常是每秒60次。正如其名称所示,它适用于动画,其中更新页面状态的频率应该与其显示频率相同。


setTimeout 只会运行一次,你可能想到的是 setInterval。请更正你的答案或者删除它。 - Ploppy
6
不,我知道自己在说什么。注意语言中的“自称使用……的语言”。 - user149341
3
好的,我现在明白了。这很令人困惑,因为你正在谈论一个特定的情况,其中函数正在递归调用自身。对于我的-1评价,抱歉,是我的错。 - Ploppy

2

取决于情况,像动画这样的情况下,requestAnimationFrame 更好,而像实时处理这样的情况下,我更喜欢 setTimeout 0

为什么?因为 requestAnimationFrame 就像是一个 setTimeout(func, 1000/60),所以 setTimeout 0 更快。

但是如果你将 requestAnimationFramesetTimeout(func, 1000/60) 进行比较。那么 requestAnimationFrame 将比 setTimeout 更加精确。


2

来自https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

唯一让我担心的是这个:

当在后台标签或隐藏的iframe中运行时,回调速率可能会降低,以提高性能和电池寿命。

但我相信只有在requestAnimationFrame递归调用自身时才会发生这种情况。

所以如果你有一些长时间运行的代码使用requestAnimationFrame,如果用户不在那个选项卡上,它可能需要更长时间。除此之外,你是在使用一个本来不打算这样做的函数,但是setTimeout也不是设计为跳过一个tick的方法...

作为建议: 通常,我发现你可以通过正确使用promise等来避免setTimeout技巧。但是我发现有些情况,尤其是在使用Angular 1.x时,我找不到比使用它更好的解决方案。

有趣的细节。通过简单的性能测试,requestAnimationFrame似乎要快得多:

console.time()
for(let i = 0; i < 100000; i++){
  requestAnimationFrame(() => {(5*5*77/3)*88});
}
console.timeEnd()

gets ~80ms(在我的电脑上)

console.time()
for(let i = 0; i < 100000; i++){
  setTimeout(() => {(5*5*77/3)*88}, 0);
}
console.timeEnd()

在我的电脑上,运行时间为约225毫秒。


1
你正在并行运行它。但是,如果需要按顺序执行一些代码,则结果将相反:0超时的链将比“帧”的链快得多。因此,方法应根据需求而定。 - dhilt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接