共计 1437 个字符,预计需要花费 4 分钟才能阅读完成。
事件循环
事件循环
的流程大抵如下:
- 所有工作都在主线程上执行,造成一个执行栈。
- 主线程发现有异步工作,就在“工作队列”之中退出一个工作事件。
- 一旦“执行栈”中的所有同步工作执行结束,零碎就会读取“工作队列”(先进先出准则)。那些对应的异步工作,完结期待状态,进入执行栈并开始执行。
- 主线程一直反复下面的第三步,这样的一个循环称为事件循环。
宏工作 & 微工作
如果工作队列中有多个异步工作,那么先执行哪个工作呢?于是在异步工作中,也进行了等级划分,分为宏工作(macrotask)和微工作(microtask);不同的 API 注册的工作会顺次进入本身对应的队列中,而后期待事件循环将它们顺次压入执行栈中执行。
+ 宏工作包含
- script(整体代码)
- setTimeout, setInterval, setImmediate,
- I/O
- UI rendering
- requestAnimationFrame()
- 微工作包含
- process.nextTick
- Promise
- Object.observe(已废除)
- MutationObserver(html5 新个性)
Node 事件循环
requestAnimationFrame
在没有 requestAnimationFrame
办法的时候,执行动画,咱们可能应用 setTimeout
或 setInterval
来触发视觉变动;然而这种做法的问题是:回调函数执行的工夫是不固定的,可能刚好就在开端,或者间接就不执行了,常常会引起丢帧而导致页面卡顿。
归根到底产生下面这个问题的起因在于机会,也就是浏览器要晓得何时对回调函数进行响应。setTimeout
或 setInterval
是应用定时器来触发回调函数的,而定时器并无奈保障可能准确无误的执行,有许多因素会影响它的运行机会,比如说:当有同步代码执行时,会先等同步代码执行结束,异步队列中没有其余工作,才会轮到本人执行。并且,咱们晓得每一次从新渲染的最佳工夫大概是 16.6 ms,如果定时器的工夫距离过短,就会造成适度渲染,减少开销;过长又会提早渲染,使动画不晦涩。
requestAnimationFrame
办法不同与 setTimeout
或 setInterval
,它是由零碎来决定回调函数的执行机会的,会申请浏览器在下一次从新渲染之前执行回调函数。无论设施的刷新率是多少,requestAnimationFrame
的工夫距离都会紧跟屏幕刷新一次所须要的工夫 。须要留神的是这个办法尽管可能 保障回调函数在每一帧内只渲染一次 ,然而 如果这一帧有太多任务执行,还是会造成卡顿的;因而它只能保障从新渲染的工夫距离最短是屏幕的刷新工夫。
requestIdleCallback
一些低优先级的工作可应用 requestIdleCallback
等浏览器不忙的时候来执行,同时因为工夫无限,它所执行的工作应该尽量是可能量化,细分的微工作(micro task)。
因为它产生在一帧的最初,此时页面布局曾经实现,所以不倡议在 requestIdleCallback
里再操作 DOM,这样会导致页面再次重绘。DOM 操作倡议在 rAF 中进行。同时,操作 DOM 所须要的耗时是不确定的,因为会导致从新计算布局和视图的绘制,所以这类操作不具备可预测性。
Promise 也不倡议在这外面进行,因为 Promise 的回调属性 Event loop 中优先级较高的一种微工作,会在 requestIdleCallback
完结时立刻执行,不论此时是否还有充裕的工夫,这样有很大可能会让一帧超过 16 ms。