事件循环机制
Node.js 事件循环机制(Event Loop)是其核心特性之一,它使得 Node.js 能够高效地处理大量并发的 I/O 操作。Node.js 基于 非阻塞 I/O,使用事件驱动的模型来实现异步编程。事件循环是 Node.js 实现异步编程的基础,它帮助 Node.js 在单线程中处理多个并发操作,同时避免了传统多线程模型中的性能开销。
事件循环的基本概念
Node.js 是单线程的,这意味着它的 JavaScript 代码是同步执行的。但是,Node.js 利用事件循环和异步 I/O 操作,使得可以在不阻塞主线程的情况下处理并发请求。事件循环是一个不断轮询的机制,它负责调度和执行异步操作。
事件循环的主要工作是:
- 监听事件(如文件 I/O、网络请求等)
- 处理回调函数
- 维护事件队列
每当有异步操作(如数据库查询、文件读写、HTTP 请求等)完成时,事件循环会将相应的回调函数推送到事件队列中,事件循环则会依次执行这些回调函数。
事件循环的执行流程
Node.js 中的事件循环实际上是通过一系列阶段来执行的,每个阶段执行特定类型的回调。事件循环的阶段如下:
-
Timers 阶段:
- 在这个阶段,事件循环会检查是否有定时器(如
setTimeout
和setInterval
)到期。如果到期,它会执行相应的回调函数。
- 在这个阶段,事件循环会检查是否有定时器(如
-
I/O Callbacks 阶段:
- 执行几乎所有的回调函数,除了定时器回调和
setImmediate()
回调。这个阶段处理的是系统的异步 I/O 操作,如文件系统操作、网络请求等。
- 执行几乎所有的回调函数,除了定时器回调和
-
Idle, Prepare 阶段:
- 这是一个准备阶段,主要用于内部操作,开发者通常不会直接操作该阶段。
-
Poll 阶段:
- 这是事件循环的核心阶段,负责查询事件队列。事件循环会在这个阶段等待事件队列中有待处理的事件。如果队列中有回调函数,它会执行这些回调。如果队列为空,则会继续等待事件。
-
Check 阶段:
- 执行
setImmediate()
注册的回调函数。setImmediate()
是一种立即执行的机制,在事件循环的 "Check" 阶段执行。注意,setImmediate()
和setTimeout()
具有不同的执行时机,setTimeout()
是基于时间延迟来调度回调,而setImmediate()
则在当前事件循环周期中立即执行。
- 执行
-
Close Callbacks 阶段:
- 处理某些关闭回调,如
socket.on('close', callback)
或fs.close()
的回调。
- 处理某些关闭回调,如
事件循环的生命周期
-
同步代码执行:
- 当 Node.js 应用启动时,主线程首先执行所有的同步代码。如果代码中存在 I/O 操作,它会被异步化,交由事件循环管理。
-
事件循环开始:
- 一旦同步代码执行完毕,事件循环开始运转,开始处理事件队列中的任务。
-
阶段执行:
- 事件循环按顺序执行上述的每个阶段。每个阶段的任务执行完成后,进入下一个阶段,直到所有回调函数都被执行完毕。
-
空闲和结束:
- 如果事件循环没有更多的任务要处理,它将进入空闲状态,直到下一次有事件到来。
分析以下代码的打印顺序
setTimeout(() => {
console.log('5----------');
}, 10);
setImmediate(() => {
console.log('3----------');
});
console.log('1----------');
setTimeout(() => {
console.log('6----------');
}, 10);
setImmediate(() => {
console.log('4----------');
});
console.log('2----------');
在node环境中的打印顺序