添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
HTML5 规范规定最小延迟时间不能小于 4ms,即 x 如果小于 4,会被当做 4 来处理。 不过不同浏览器的实现不一样,比如,Chrome 可以设置 1ms,IE11/Edge 是 4ms。 setTimeout 注册的函数 fn 会交给浏览器的定时器模块来管理,延迟时间到了就将 fn 加入主进程执行队列,如果队列前面还有没有执行完的代码,则又需要花一点时间等待才能执行到 fn,所以实际的延迟时间会比设置的长。如在 fn 之前正好有一个超级大循环,那延迟时间就不是一丁点了。
1
2
3
4
5
6
7
8
9
10
11
( function testSetInterval ( ) {
let i = 0 ;
const start = Date . now ( ) ;
const timer = setInterval ( ( ) = > {
i += 1 ;
i === 5 && clearInterval ( timer ) ;
console . log ( ` $ { i } 次开始 ` , Date . now ( ) - start ) ;
for ( let i = 0 ; i < 100000000 ; i ++ ) { }
console . log ( ` $ { i } 次结束 ` , Date . now ( ) - start ) ;
} , 100 ) ;
} ) ( ) ;
requestAnimationFrame 并不是定时器,但和 setTimeout 很相似,在没有 requestAnimationFrame 的浏览器一般都是用 setTimeout 模拟。 requestAnimationFrame 跟屏幕刷新同步,大多数屏幕的刷新频率都是 60Hz,对应的 requestAnimationFrame 大概每隔 16.7ms 触发一次,如果屏幕刷新频率更高,requestAnimationFrame 也会更快触发。基于这点,在支持 requestAnimationFrame 的浏览器还使用 setTimeout 做动画显然是不明智的。 在不支持 requestAnimationFrame 的浏览器,如果使用 setTimeout/setInterval 来做动画,最佳延迟时间也是 16.7ms。 如果太小,很可能连续两次或者多次修改 dom 才一次屏幕刷新,这样就会丢帧,动画就会卡;如果太大,显而易见也会有卡顿的感觉。 有趣的是,第一次触发 requestAnimationFrame 的时机在不同浏览器也存在差异,Edge 中,大概 16.7ms 之后触发,而 Chrome 则立即触发,跟 setImmediate 差不多。按理说 Edge 的实现似乎更符合常理。 但相邻两次 requestAnimationFrame 的时间间隔大概都是 16.7ms,这一点是一致的。当然也不是绝对的,如果页面本身性能就比较低,相隔的时间可能会变大,这就意味着页面达不到 60fps。 Promise
Promise 是很常用的一种异步模型,如果我们想让代码在下一个事件循环执行,可以选择使用 setTimeout(0)、setImmediate、requestAnimationFrame(Chrome) 和 Promise。 而且 Promise 的延迟比 setImmediate 更低,意味着 Promise 比 setImmediate 先执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function testSetImmediate ( ) {
const label = 'setImmediate' ;
console . time ( label ) ;
setImmediate ( ( ) = > {
console . timeEnd ( label ) ;
} ) ;
}
function testPromise ( ) {
const label = 'Promise' ;
console . time ( label ) ;
new Promise ( ( resolve , reject ) = > {
resolve ( ) ;
} ) . then ( ( ) = > {
console . timeEnd ( label ) ;
} ) ;
}
testSetImmediate ( ) ;
testPromise ( ) ;
可以肯定的是,在各 JS 环境中,Promise 都是最先执行的,setTimeout(0)、setImmediate 和 requestAnimationFrame 顺序不确定。 process.nextTick
process.nextTick 是 Nodejs 的 API,比 Promise 更早执行。 事实上,process.nextTick 是不会进入异步队列的,而是直接在主线程队列尾强插一个任务,虽然不会阻塞主线程,但是会阻塞异步任务的执行,如果有嵌套的 process.nextTick,那异步任务就永远没机会被执行到了。 使用的时候要格外小心,除非你的代码明确要在本次事件循环结束之前执行,否则使用 setImmediate 或者 Promise 更保险。

—– Promise 是很常用的一种异步模型,如果我们想让代码在下一个事件循环执行,可以选择使用 setTimeout(0)、setImmediate、requestAnimationFrame(Chrome) 和 Promise

其中貌似有点问题,promise 的异步代码不会在【下一个事件循环】执行,而是在【本次事件循环】结束之后执行。

@sunyuhui 是的,nextTick 和 promise 都属于 microtask,是在 idle 阶段执行的,所以优先级会比 timeout,timeinterval 这些在 check 阶段执行的要早

有多少是空心 www.kxhtml.com 这样的众包网站:价格标准 100 元/页面,专属项目经理管这管那质量,不小心点了退款钱到了,靠谱技工为个好评就差做牛做马了,要不去看看?www.kxhtml.com

发现个问题请教下,setInterval demo 中的在 Chrome 和 nodejs 环境下,执行差别很大。在 Chrome 下前一次结束和下一次开始的时间差一般在 1ms,但是在 nodejs 环境下差别 1000ms 以上

setTimeout 注册的函数 fn 会交给浏览器的定时器模块来管理,延迟时间到了就将 fn 加入主进程执行队列这里是不是写错了。应该是延迟时间到了,就将 fn 加入等待队列吧,而不是主进程执行队列

@TAT.云中飞扬 我的理解是一直在另一个队列中等待的,当主进程执行队列空闲时,另一个队列 的任务才会加入到主进程队列,而不是一开始就加入主进程队列了。这应该就是你所说的 “加入主进程队列也有一个等待的过程”

本文不如这篇 http://www.alloyteam.com/2015/10/turning-to-javascript-series-from-settimeout-said-the-event-loop-model/