注:此处仅对比独立线程的异步函数,使用 postMessage 等多线程方式暂不考虑。另外 Promise 使用的是 micro task,并没有离开当前消息循环,这里也暂不考虑。
截至目前(2018.7.6)有四个函数可以用于异步任务调用:
setTimeout
setInterval
requestAnimationFrame
requestIdleCallback
TL;DR
setTimeout
和 setInterval
适合后台运行一些队列任务,但纯计算任务应该使用 Web Worker;requestAnimationFrame
适合处理实时的 UI 任务,requestIdleCallback
适合处理耗时的更新 UI 操作。
setTimeout
和 setInterval
setTimeout
和 setInterval
在目前浏览器的实现上应该是类似的,添加一个延迟指定时间的定时器任务,区别是 setInterval
定时器将循环执行,而 setTimeout
仅执行一次。
setTimeout
和 setInterval
的第一个参数可以是字符串或函数,如果是字符串则会隐式调用内部解释器,类似 eval
或 new Function
。第三个及后面的参数如果指定,则会被传入回调函数中(IE9以下不支持,但可以 Pollyfill)
第二个参数用来指定延迟的毫秒数,如果不声明默认为 DOM_MIN_TIMEOUT_VALUE
,如果比这个值小也会被强行置为这个值。在最新版本的主流浏览器中这个值大概是 4ms。
在 Chrome 中(其他浏览器暂未测试),当标签页不在前台运行时,这个最小值会变成 1000ms。猜测当页面处在隐藏的 iframe 中也会有类似的行为,暂未确定。
在 Firefox 中,如果脚本被识别为某些页面统计脚本,例如 GA,则这个最小值会变成 10000ms。
据某些 Web 文章记载,过去的浏览器曾有以下行为:
setInterval
不同于setTimeout
,其最小延迟时间为 10mssetTimeout
和setInterval
当计算机使用电池时使用系统定时器(最小延迟 1/60s)
requestAnimationFrame
requestAnimationFrame
的行为类似于 setTimeout 仅使用第一个参数的情况,且只能传递函数作为参数。回调函数可以接收一个值等于 performance.now()
的参数。
requestAnimationFrame
通常来说使用的是 Web 标准帧率(延迟 1/60s 执行)
requestAnimationFrame
在非前台的标签页或隐藏的 iframe 中会停止运行
requestIdleCallback
requestIdleCallback
的参数与 requestAnimationFrame
完全一致,但它可以指定第二个参数。requestIdleCallback
在下一帧到来时如果浏览器不处于空闲状态,则会继续延迟一帧执行,直到浏览器进入空闲,或者第二个参数的 timeout 属性这么多毫秒过去。