跟着coderwhy学习
1.Node的事件循环
- 浏览器中的EventLoop是根据HTML5定义的规范来实现的,不同的浏览器可能会有不同的实现,而Node中是由libuv实现的。
- 这里给出一个Node的架构图:
- 我们会发现libuv中主要维护了一个EventLoop和worker threads(线程池);
- EventLoop负责调用系统的一些其他操作:文件的IO、Network、child-processes等
- libuv是一个多平台的专注于异步IO的库,它最初是为Node开发的,但是现在也被使用到Luvit、Julia、pyuv等其他地方;
2.Node事件循环的阶段
- 事件循环像是一个桥梁,是连接着应用程序的JavaScript和系统调用之间的通道:
- 无论是我们的文件IO、数据库、网络IO、定时器、子进程,在完成对应的操作后,都会将对应的结果和回调函数放到事件循环(任务队列)中;
- 事件循环会不断的从**任务队列中取出对应的事件(回调函数)**来执行;
- 但是一次完整的事件循环Tick分成很多个阶段:
- 定时器(Timers):本阶段执行已经被 setTimeout() 和 setInterval() 的调度回调函数。
- 待定回调(Pending Callback):对某些系统操作(如TCP错误类型)执行回调,比如TCP连接时接收到ECONNREFUSED。
- idle, prepare:仅系统内部使用。
- 轮询(Poll):检索新的 I/O 事件;执行与 I/O 相关的回调;
- 检测(check):setImmediate() 回调函数在这里执行。
- 关闭的回调函数:一些关闭的回调函数,如:socket.on('close', ...)。
3.Node事件循环的阶段图解
4.Node的宏任务和微任务
- 我们会发现从一次事件循环的Tick来说,Node的事件循环更复杂,它也分为微任务和宏任务:
- 宏任务(macrotask):setTimeout、setInterval、IO事件、setImmediate、close事件;
- 微任务(microtask):Promise的then回调、process.nextTick、queueMicrotask;
- 但是,Node中的事件循环不只是 微任务队列和 宏任务队列:
- 微任务队列:
- next tick queue:process.nextTick;
- other queue:Promise的then回调、queueMicrotask;
- 宏任务队列:
- timer queue:setTimeout、setInterval;
- poll queue:IO事件;
- check queue:setImmediate;
- close queue:close事件;
- 微任务队列:
5.Node事件循环的顺序
- 所以,在每一次事件循环的tick中,会按照如下顺序来执行代码:
- next tick microtask queue;
- other microtask queue;
- timer queue;
- poll queue;
- check queue;
- close queue;