当启动Node.js的时候,会初始化事件循环(event loop),事件循环包含6个阶段:
libuv中的源码:
int uv_run(uv_loop_t* loop, uv_run_mode mode) { int timeout; int r; int ran_pending; r = uv__loop_alive(loop); if (!r) uv__update_time(loop); while (r != 0 && loop->stop_flag == 0) { uv__update_time(loop); uv__run_timers(loop); ran_pending = uv__run_pending(loop); uv__run_idle(loop); uv__run_prepare(loop); timeout = 0; if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); uv__io_poll(loop, timeout); uv__run_check(loop); uv__run_closing_handles(loop); if (mode == UV_RUN_ONCE) { /* UV_RUN_ONCE implies forward progress: at least one callback must have * been invoked when it returns. uv__io_poll() can return without doing * I/O (meaning: no callbacks) when its timeout expires - which means we * have pending timers that satisfy the forward progress constraint. * * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from * the check. */ uv__update_time(loop); uv__run_timers(loop); } r = uv__loop_alive(loop); if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) break; } /* The if statement lets gcc compile it to a conditional store. Avoids * dirtying a cache line. */ if (loop->stop_flag != 0) loop->stop_flag = 0; return r; }
- timer阶段:对应的是源码中的uv_run_timer(loop)方法,主要执行setTimeout()和setInterval()方法中到期的callback;
- pending callbacks(I/O)阶段:对应的是源码中的uv_run_pending(loop)方法,主要是执行推迟到下一循环I/O操作的callbacks;
- idle,prepare阶段:对应源码中的uv_run_idle(loop)和uv_run_prepare(loop)方法,主要是Node自己内部使用(不用考虑);
- poll阶段:对应源码中的uv_io_poll(loop,timeout)方法,检索新的I/O事件;执行I/O相关的callbacks;除此之外,poll还负责检测是否有timer的callback到达时间,并且还未执行那么就循环至timer阶段执行timer的callback;
- check阶段:对应源码中的uv_run_check(loop)方法,主要执行setImmediate()方法的callback;
- close callbacks阶段:对应源码中的uv_run_closing_handles(loop)方法,主要执行一些close事件的callback.
const {readFile} = require('fs'); const {resolve} = require('path'); setImmediate(() => console.log(`[check阶段:] setImmediate 回调 1`)); setTimeout(() => console.log(`[timer阶段:] setTimeout 回调 1`), 0); setTimeout(() => console.log(`[timer阶段:] setTimeout 回调 2`), 0); setImmediate(() => console.log(`[check阶段:] setImmediate 回调 2`)); setTimeout(() => console.log(`[timer阶段:] setTimeout 回调 3`), 0); readFile(resolve(__dirname, './exec.js'), 'utf-8', data => { console.log(`[I/O阶段] readFile 回调 1`); }); Promise.resolve() .then(() => { console.log(`[...待切入下一阶段] Promise 回调 1`); console.log(`[...待切入下一阶段] Promise 回调 1`); console.log(`[...待切入下一阶段] Promise 回调 1`); console.log(`[...待切入下一阶段] Promise 回调 1`); console.log(`[...待切入下一阶段] Promise 回调 1`); }) .then(() => { console.log(`[...待切入下一阶段] Promise 回调 3`); console.log(`[...待切入下一阶段] Promise 回调 3`); console.log(`[...待切入下一阶段] Promise 回调 3`); }); process.nextTick(() => console.log(`[...待切入下一阶段] nextTick 回调 1`)); process.nextTick(() => { console.log(`[...待切入下一阶段] nextTick 回调 2`); Promise.resolve() .then(() => { console.log(`[...待切入下一阶段] nextTick中的Promise 回调 2`); setImmediate(() => console.log(`[check阶段:] nextTick中的setImmediate 回调 5`)); setTimeout(() => console.log(`[timer阶段:] nextTick中的setTimeout 回调 5`), 0); }) .then(() => { console.log(`[...待切入下一阶段] nextTick中的Promise 回调 4`); process.nextTick(() => console.log(`[...待切入下一阶段] nextTick中的Promise中的nextTick 回调 3`)); }) });
运行结果:
[...待切入下一阶段] nextTick 回调 1
[...待切入下一阶段] nextTick 回调 2
[...待切入下一阶段] Promise 回调 1
[...待切入下一阶段] Promise 回调 1
[...待切入下一阶段] Promise 回调 1
[...待切入下一阶段] Promise 回调 1
[...待切入下一阶段] Promise 回调 1
[...待切入下一阶段] nextTick中的Promise 回调 2
[...待切入下一阶段] Promise 回调 3
[...待切入下一阶段] Promise 回调 3
[...待切入下一阶段] Promise 回调 3
[...待切入下一阶段] nextTick中的Promise 回调 4
[...待切入下一阶段] nextTick中的Promise中的nextTick 回调 3
[timer阶段:] setTimeout 回调 1
[timer阶段:] setTimeout 回调 2
[timer阶段:] setTimeout 回调 3
[timer阶段:] nextTick中的setTimeout 回调 5
[check阶段:] setImmediate 回调 1
[check阶段:] setImmediate 回调 2
[check阶段:] nextTick中的setImmediate 回调 5
[I/O阶段] readFile 回调 1
参考文章:
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/