参考
浏览器端
到底什么是事件循环 Event loop in JavaScript (b站搬运的油管视频)
Loupe—可视化查看event loop
https://mp.weixin.qq.com/s/m3a6vjp8-c9a2EYj0cDMmg
深入JavaScript中的EventLoop(b站另外一个搬运的油管视频)(包含异步api回调队列 和 u渲染 两部分动画演示)
对应油管地址,speaker is chrome develoer
https://www.youtube.com/watch?v=cCOL7MC4Pl0&t=1442s
事件循环是如何影响页面渲染的?(非常好博客 理解页面渲染以及 requestAnimationFrame,setTimeout 4ms延迟)
浏览器进程线程详解
Event Loop 这个循环你晓得么?(附GIF详解)(饿了么前端)(附node event loop)
包含浏览器端 和 node端
详解JavaScript中的Event Loop(事件循环)机制 (知乎专栏)
通杀Event Loop面试题! (b站 培训机构讲的 非常好)
task 介绍
Tasks, microtasks, queues and schedules (博客 深入JavaScript中的EventLoop 同一个大佬,这边博客又提到了到底什么是事件循环 Event loop in JavaScript )
0 前提
1. 名词
1.1 微任务 MicroTask
1.2 宏任务 MacroTask
浏览器端: 定时器(setTimeout 和 setInterval)
ajax
UI 渲染
页面交互
DOM事件 requestAnimationFrame
node端: 定时器(setTimeout 和 setInterval)
I/0
1.3 任务队列 task queue
1.4 node端事件循环独有的API
2. 浏览器端 event loop
2.1 任务队列分macro task queue和 micro task,一次事件循环,只会从宏任务队列中取出一个执行,然后清空所有微任务队列, 如此循环。
(下面图上 callback queue 没有区分macro 和 micro)
2.2 UI 渲染和交互的处理是通过 Task Queue 来调度的
因此耗时任务会导致渲染和交互任务得不到调用,也就是页面“卡死”。
如果设计一个耗时任务
循环 API | 队列类型 | 期间页面能否交互? | 每秒执行次数 |
---|---|---|---|
while(true) | 当前任务 | 否 | 701665.8 |
Promise | Microtask Queue | 否 | 609555.4 |
setTimeout | Task Queue | 是 | 208.3 |
requestAnimationFrame | Task Queue | 是 | 59 |
- 单个的耗时任务和 Microtask Queue 都会阻塞页面交互
(因为JavaScript 有 “run-to-completion” 的特性,以及在执行下个task是,要清空当前micro task)
- Macro Task 则不影响。 因为 Macro Task 之间浏览器有机会会插入 UI 任务。
扩展:一下代码页面背景是否会闪现一下红色?直觉总会有这样的担心
document.body.style.background = 'red';
document.body.style.background = 'white';
答案:
背景会稳定地呈现白色。 因为 JavaScript “run-to-completion” 的特性,在上述两行代码之间不可能插入渲染任务
3. node端 event loop
3.1 node端事件循环不同于浏览器端,一次循环包含六个阶段,主要关注一下三个阶段
- timers (定时器执行阶段)
- poll (I/0 callback执行阶段,大部分异步api回调在这个阶段执行,)
(不同于 I/0 callbacks 阶段,目前这个部分和poll阶段 从网上看到的资料讲解的不太统一,还没搞明白,暂时把i/o回调放在这里)
- check ( setImmediate 执行阶段)
注意: process.nextTick() 不存在以上任何一个阶段,而是介于每个阶段的中间。
事实上,每个阶段都包含三个队列(这里把process.nextTick包含到以上提到的阶段里面了,便于理解)
其中process.nextTick优先级高于promise
3.2 不确定定性
setTimeout(function() {console.log("setTimeout")}, 0)
setImmediate(() => {
console.log('setImmediate');
});
以上代码 那个先执行?
答案: 随机,都有可能。
因为: