EventLoop之Node事件循环

4/23/2021 EventLoopNode

# 文章目录

# 一、什么是事件循环?

通俗来说就是我们所编写的 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

解析:
在这里插入图片描述
结果:

/**
 * 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
最后更新于: 2021年9月15日星期三晚上10点10分
Dawn
DDRKirby(ISQ)