node 第四天 EventLoop node的事件循环特殊点

  1. node重要性质

事件驱动 非阻塞 I/O 单线程 异步回调
对 node Event Loop(事件循环)的理解特别重要 想必每一位前端对于浏览器的Event Loop已经有所了解
但是在学习node的路上, 理解node的Event Loop也是不可或缺的

  1. 版本变迁

version < node11
简单概述 Node 11版本之前 任务分配是 先执行全局Script代码,执行完同步代码调用栈清空后,先从微任务队列Next Tick Queue中依次取出所有的任务放入调用栈中执行,再从微任务队列Other Microtask Queue中依次取出所有的任务放入调用栈中执行。然后开始宏任务的6个阶段,每个阶段都将该宏任务队列中的所有任务都取出来执行(注意,这里和浏览器不一样,浏览器只取一个),每个宏任务阶段执行完毕后,开始执行微任务,再开始执行下一阶段宏任务,以此构成事件循环。

version >= node11
Node11之后,也是每个 Macrotask 执行完后,就去执行 Microtask 了,和浏览器的模型一致。

setTimeout(() => {
  console.log('t1');
  Promise.resolve().then(function() {
    console.log('p1');
  });
}, 0);

setTimeout(() => {
  console.log('t2');
  Promise.resolve().then(function() {
    console.log('p2');
  });
}, 0);
//version < node11: t1 t2 p1 p2 
//version >= node11: t1 p1 t2 p2 
  1. node 两个特别的环境函数需要注意 (这里环境函数不是专业名词)
  • process.nextTick (微)
  • setImmediate (宏)

process.nextTick方法可以在当前"执行栈"的尾部----下一次Event Loop(主线程读取"任务队列")之前----触发回调函数。也就是说,它指定的任务总是发生在所有异步任务之前。
setImmediate方法则是在当前"任务队列"的尾部添加事件,也就是说,它指定的任务总是在下一次Event Loop时执行,这与setTimeout(fn, 0)很像

  • process.nextTick 可以在当前"执行栈"的尾部----下一次Event Loop(主线程读取"任务队列")之前----触发回调函数; 如果在一个执行栈中被注册, process.nextTick总是先于setImmediate和setTimeout执行

  • setImmediate 在当前"任务队列"的尾部添加事件,也就是说,它指定的任务总是在下一次Event Loop时执行 和 setTimeout如果处于同一个执行栈, 不能确定谁先执行(由多种因素决定)

  • 有一种情况setImmediate一定比setTimeout先执行: setImmediate和setTimeout同处在一个setImmediate调用栈里面

//示例一
setImmediate(()=> {
  console.log(1);
});

setTimeout(()=> {
  console.log(2);
}, 0);
//结果可能是 1 2 也可能是 2  1

//示例二
setImmediate(()=> {
  setImmediate(()=> {
    console.log(1);
    setImmediate(()=> {
        console.log(2);
    });
  });
  setTimeout(()=> {
    console.log(3);
  }, 0);
});
//结果: 1 3 2
  • 不要觉得奇怪: “上面的代码即使到了编译那一层居然还有有不同的运行结果(不可控)”
  1. 实际上setImmediate的出现正是为了我们能够在Event Loop再插一手

多个process.nextTick语句总是在当前"执行栈"一次执行完,多个setImmediate可能则需要多次loop才能执行完。事实上,这正是Node.js 10.0版添加setImmediate方法的原因,否则像下面这样的递归调用process.nextTick,将会没完没了,主线程根本不会去读取"事件队列"!

//示例一
process.nextTick(function foo() {
   process.nextTick(foo);
});
setTimeout(function callMe() {
  console.log('call me ! ! !')
})
//callMe永远不会被调用, 因为 setTimeout(宏)总是需要等待当前执行栈的微任务清空

//示例二
setImmediate(function foo() {
   setImmediate(foo);
});
setTimeout(function callMe() {
  console.log('call me ! ! !')
})
//callMe将会在第一个或第二个事件队列被调用

node.js
皇权特许 先斩后奏 ~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值