近日在论坛上看到一篇文章讲node和谷歌浏览器的eventloop的区别,由于看到写的还不错,我表示了确定。但没过多久一位坛友却说node11结果不同,我说怎么可能不同。接着坛友贴了个代码,我试着运行了一下,啪啪打脸!node
先上被啪啪打脸的代码:git
setTimeout(() => { console.log('timer1'); Promise.resolve().then(function() { console.log('promise1'); }); }, 0); setTimeout(() => { console.log('timer2'); Promise.resolve().then(function() { console.log('promise2'); }); }, 0); 复制代码
了解node的eventloop的同窗应该会这样想:github
那么若是机器运行良好就是如下结果:promise
timer1
timer2
promise1
promise2
复制代码
node10运行结果确实是这样,是没问题的。但node11运行后竟然是:浏览器
timer1
promise1
timer2
promise2
复制代码
挺吃惊的,但吃惊事后仍是仔细去翻node的修改日志,在node 11.0 的修改日志里面发现了这个:markdown
而后分别看了20002和22842的PR,发如今 #22842 在lib/timers.js里面有如下增长:异步
这两个是什么意思呢?oop
提示一下runNextTicks()就是process._tickCallback()。用过的可能知道这个就是除了处理一些异步钩子,而后就是执行微任务队列的。因而我增长了两行process._tickCallback()在setTimeout方法尾部,再使用node10运行,效果果真和node11一致,代码以下:spa
setTimeout(() => { console.log('timer1'); Promise.resolve().then(function() { console.log('promise1'); }); process._tickCallback(); // 这行是增长的! }, 0); setTimeout(() => { console.log('timer2'); Promise.resolve().then(function() { console.log('promise2'); }); process._tickCallback(); // 这行是增长的! }, 0); 复制代码
固然是为了和浏览器更加趋同。日志
了解浏览器的eventloop可能就知道,浏览器的宏任务队列执行了一个,就会执行微任务。
简单的说,能够把浏览器的宏任务和node10的timers比较,就是node10只有所有执行了timers阶段队列的所有任务才执行微任务队列,而浏览器只要执行了一个宏任务就会执行微任务队列。
如今node11在timer阶段的setTimeout,setInterval...和在check阶段的immediate都在node11里面都修改成一旦执行一个阶段里的一个任务就马上执行微任务队列。
因此在生产环境建议仍是不要特地的去利用node和浏览器不一样的一些特性。即便是node和浏览器相同的特性,但规范没肯定的一些特性,也建议当心使用。不然一次小小的node升级可能就会形成一次线上事故,而不仅是啪啪打脸这么简单了。