Node事件循环机制

Node的事件循环机制

一、什么是事件循环

在node应用程序启动后,并不会立即进入事件循环,而是先执行输入代码,从上到下开始执行,同步API立即执行,异步API交给C++维护libuv的线程执行,异步API的回调函数被注册到对应的poll事件队列中。当所有输入代码执行完成后,开始进入事件循环

   ┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘      ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll           │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
│  ┌──────────┴────────────┐      └───────────────┘
│  │        check          │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
   └───────────────────────┘
//注意:途中每个方框被称为事件循环的一个阶段,这六个阶段为一轮事件循环 Event loop
  • timer阶段(定时器):执行setTimeout(callback)和setInterval(callback)
  • I/O callbacks阶段(I/O回调):执行某些系统操作的回调(例如TCP错误类型)
  • idle、prepare阶段(空转):仅node内部使用
  • poll阶段(轮询):获取新的I/O事件,例如操作读取文件
  • check阶段(检查):执行 setImmediate() 设定的callbacks;
  • close callbacks阶段(关闭回调):比如 socket.on(‘close’, callback) 的callback会在这个阶段执行;

如果event loop进入了poll阶段,且代码未设定timer,将会发生下面情况:

  • 如果poll queue不为空,event loop将同步的执行queue里面的callback,直至queue为空,或者执行的callback到达系统上限制

  • 如果poll queue为空:

    • 如果代码已经被setImmediate()设定callback,event loop将结束poll阶段进入 check阶段并执行check阶段的queue
    • 如果代码没有设定setImmediate(callback),event loop将阻塞在该阶段等待callback加入poll queue,一旦达到就立即执行

如果event loop 进入poll阶段,且代码设定了timer:

  • 如果poll queue进入空状态时(即poll阶段为空闲状态),event loop将检查timers,如果1个或多个timers时间已达到,event loop将按循环顺序进入timers阶段,并执行timer queue

    GitHub

二.nextTicksetImmediate

  • process.nextTick不属于时间循环的任何一个阶段,它属于该阶段与下阶段之间的过渡,即本阶段执行结束,进入下一个阶段前,所以要执行回调(插队)
  • setImmediate的回调处于check阶段,当poll阶段的队列为空,且check阶段的时间队列存在的时候,要切换到check阶段执行
    • setImmediate()被设计在 poll 阶段结束后立即执行回调;
    • setTimeout()被设计在指定下限时间到达后执行回调;
setTimeout(() => {
  setTimeout(() => {
    console.log(1);
  }, 0);
  setImmediate(() => {
    console.log(2);
  });
}, 0);
// 2 1
setTimeout(() => {
    console.log(1);
  }, 0);
  setImmediate(() => {
    console.log(2);
  });
// 1  2或 2  1

三.nextTick和Promise

理解成一个微任务不属于事件循环的一部分,会在其所处的时间循环最后,时间循环进入下一个阶段前执行

console.log("start");
setTimeout(() => {
  console.log("timer1");
  Promise.resolve().then(function () {
    console.log("promise1");
  });
}, 0);
setTimeout(() => {
  console.log("timer2");
  Promise.resolve().then(function () {
    console.log("promise2");
  });
}, 0);
Promise.resolve().then(function () {
  console.log("promise3");
});
console.log("end");
process.nextTick(() => {
  console.log(1);
});
//start->end->1->promise3->timer1->promise1->timer2->promise2

Node是单线程的,主线程将所有任务都放在循环队列中,然后由底层的libuv库从循环事件队列中取出任务分配给不同的线程去处理,主线程同时也会进行回调处理,整个过程形成事件循环

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值