Node.js 事件循环机制

当启动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/

https://github.com/libuv/libuv

猜你喜欢

转载自blog.csdn.net/qq_2575896094/article/details/80212343