![](https://img.haomeiwen.com/i1632709/fe166891b0d40457.png)
一、介绍
在了解事件循环之前,首先需要了解两个概念:
(1)调用栈和任务队列
![](https://img.haomeiwen.com/i1632709/88423dbf90a0d6b3.png)
主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数。—— JavaScript 运行机制详解:再谈Event Loop,阮一峰
(2)宏任务和微任务是什么?划分的依据是什么?
宏任务(Task/macrotask) 是严格按照时间顺序压栈和执行的,所以浏览器能够使得 JavaScript 内部任务与 DOM 任务能够有序的执行。当一个 task 执行结束后,在下一个 task 执行开始前,浏览器可以对页面进行重新渲染。
微任务(Microtask) 通常来说就是需要在当前 task 执行结束后立即执行的任务,例如需要对一系列的任务做出回应,或者是需要异步的执行任务而又不需要分配一个新的 task,这样便可以减小一点性能的开销。
Task:script(全局任务),事件回调,XHR回调,setTimeout,setInterval,setImmediate(node独有),I/O,UI rendering
Microtask:更新应用程序状态的任务,包括Promise回调,MutationObserver,process.nextTick(node独有),Object.observe(废弃)
【注意】:
- 宏任务和微任务的执行方式在浏览器和 Node 中有差异。
- 关于
Promise
需要注意的:promise 的 then 和 catch 才是 microtask,本身的内部代码不是。
new Promise((resolve, reject) => {
console.log('同步');
resolve()}
).then(() => {
console.log('异步');
})
☛ Finally,什么是事件循环?
主线程从“任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为 Event Loop(事件循环)。
二、事件循环(浏览器)
![](https://img.haomeiwen.com/i1632709/0c6ef854750f6ad6.png)
![](https://img.haomeiwen.com/i1632709/b29e3d17ea5083bd.png)
浏览器环境下,microtask 的任务队列是每个 macrotask 执行完之后执行。
三、事件循环(Node.js)
JavaScript引擎作为将JavaScript解释为机器码的工具,分别运行在浏览器和Node中。而根据上下文的不同,Event loop也有不同的实现。
![](https://img.haomeiwen.com/i1632709/73b4298bc1423e9b.png)
在浏览器中,html规范定义了Event loop,具体的实现则交给不同的厂商去完成,而Node采用V8 作为js的解析引擎,在I/O处理方面使用了自己设计的libuv,libuv是一个基于事件驱动的跨平台抽象层,封装了不同操作系统一些底层特性,对外提供统一的API,事件循环机制也是它里面实现的。
![](https://img.haomeiwen.com/i1632709/d132282baeb984de.png)
根据 Node.js 官方介绍,每次事件循环都包含了6个阶段,对应到 libuv 源码中的实现。
事件循环会无限次地执行,一轮又一轮。只有异步任务的回调函数队列清空了,才会停止执行。
![](https://img.haomeiwen.com/i1632709/0141bf9e52862ecd.png)
在Node.js中,microtask 会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行 microtask 队列的任务。
process.nextTick()
并没有在 Event Loop 的执行阶段中,而是在 Event Loop 两个阶段之间运行,根据上面说的,process.nextTick()
属于 microtask 任务类型。也就是process.nextTick()
有可能插入在 Event Loop各个阶段中。
关于Node定时器(process.nextTick、setTimeout、setImmediate)方面的内容,请参阅 Node 定时器详解,阮一峰
四、参考
- JavaScript 运行机制详解:再谈Event Loop,阮一峰
- Node 定时器详解,阮一峰
- Tasks, microtasks, queues and schedules
- [译] 深入理解 JavaScript 事件循环(二)— task and microtask
- 一篇文章教会你Event loop——浏览器和Node
- 什么是浏览器的事件循环(Event Loop)?
- 深入理解js事件循环机制(Node.js篇)
- 深入理解js事件循环机制(浏览器篇)
- 浏览器和Node不同的事件循环(Event Loop)
- 事件循环机制的那些事
- node中的Event模块(上)
- 8 张图帮你一步步看清 async/await 和 promise 的执行顺序
网友评论