EventLoop in Node
参考 https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
https://github.com/creeperyang/blog/issues/26
http://docs.libuv.org/en/v1.x/design.html
更深入需研究libuv,TODO
EventLoop,是在JS单线程的基础上,解决非阻塞IO操作的。通过在任何时候转移操作给内核。
大部分内核都是多线程的,可以在后台执行多个操作。当完成一件操作,内核告诉Node.js,然后对应的callback可以被添加到poll 队列,最后被执行。
Node中的EventLoop由libuv实现。
I/O (or event) loop是libuv的核心部分。
构建IO操作,将其绑定到一个线程中。
利用平台/操作系统的轮训机制,在IO任务完成后执行回调。
┌───────────────────────────┐
┌─>│ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘ ┌───────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │<─────┤ connections, │
│ └─────────────┬─────────────┘ │ data, etc. │
│ ┌─────────────┴─────────────┐ └───────────────┘
│ │ check │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │
└───────────────────────────┘
每个Phases都是一个先进先出队列
Phases Overview
-
timers:
setTimeout()
andsetInterval()
的回调. -
pending callbacks: 系统操作的回调,比如TCP errors。
-
idle, prepare: 仅内部使用。
-
poll: I/O回调,队列清空之后,如果check阶段队列不为空,结束该阶段执行check队列,否则持续等待;
poll队列清空之后会检查timers回调队列。 -
check:
setImmediate()
回调。 -
close callbacks: close的对调, 比如
socket.on('close', ...)
.
process.nextTick
不属于EventLoop,加入nextTickQueue
队列。
nextTickQueue
会在当前操作完成之后执行,不管在eventLoop哪个阶段。
process.nextTick() vs setImmediate()
process.nextTick()立即在本阶段执行回调;当前阶段的最后,下个阶段之前。
setImmediate()只能在 check 阶段执行回调。