# 文章目录
# 一、什么是事件循环?
通俗来说就是我们所编写的 Javascript 和浏览器或者 Node 之间的一个桥梁。
浏览器的事件循环是我们编写的 Javascript 代码和浏览器 API 调用(setTimeout/AJAX/监听事件)的一个桥梁,桥梁之间他们通过回调函数进行通信。
Node 的事件循环是一个我们编写的 JavaScript 代码的系统调用(file system/network 等)之间的一个桥梁,桥梁之间他们通过回调函数进行通信。
连接两个东西之间的桥梁。
# 二、进程与线程
进程和线程是操作系统中的两个概念:
- 进程(process):计算机已经运行的程序
- 线程(thread):操作系统能够运行运算调度的最小单元
听起来很抽象,直观一点:
- 进程:启动一个应用程序,就会默认启动一个进程(也有可能是多个)
- 线程:每一个进程中,都会启动一个线程用来执行程序中的代码,这个线程被称为主线程;
所以我们也可以说,进程是线程的容器
抽象表达:
工厂 => 车间 => 工人(多人)
操作系统 => 进程 => 线程
# 三、Node 架构分析
浏览器中的 EventLoop 是根据 HTML5 定义的规范来实现的,不同的浏览器可能会有不同的实现,而 Node 中是由 libuv 实现的。
我们来看在很早就给大家展示的 Node 架构图:
- 我们会发现 libuv 中主要维护了一个 EventLoop 和 worker threads(线程池);
- EventLoop 负责调用系统的一些其他操作:文件的 IO、Network、child-processes 等
libuv 是一个多平台的专注于异步 IO 的库,它最初是为 Node 开发的,但是现在也被使用到 Luvit、Julia、pyuv 等其
他地方;
阶段概述
- 定时器:本阶段执行已经被 setTimeout() 和 setInterval() 的调度回调函数。
- 待定回调:执行延迟到下一个循环迭代的 I/O 回调。
- idle, prepare:仅系统内部使用。
- 轮询:检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 setImmediate() 调度的之外),其余情况 node 将在适当的时候在此阻塞。
- 检测:setImmediate() 回调函数在这里执行。
- 关闭的回调函数:一些关闭的回调函数,如:socket.on(‘close’, …)。
Node 的事件循环队列:
- ticks 队列
- 其他微任务队列
- timers 队列:setTimeout
- I/O 队列
- setImmediate 队列
- close 队列
面试题:
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
console.log("script start");
setTimeout(() => {
console.log("setTimeout0");
}, 0);
setTimeout(() => {
console.log("setTimeout2");
}, 300);
setImmediate(() => console.log("setImmediate"));
process.nextTick(() => console.log("nextTick1"));
async1();
process.nextTick(() => console.log("nextTick2"));
new Promise((resolve) => {
console.log("promise1");
resolve();
console.log("promise2");
}).then(() => {
console.log("promise3");
});
console.log("script end");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
解析:
结果:
/**
* script start
* async1 start
* async2
* promise1
* promise2
* script end
* nextTick1
* nextTick2
* async1 end
* promise3
* setTimeout0
* setImmediate
* setTimeout2
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15