前端碎碎念 之 nextTick, setTimeout 以及 setImmediate 三者的实行递次

『前端碎碎念』系列会纪录我日常平凡看书或许看文章遇到的题目,平常都是比较基本然则轻易忘记的知识点,你也能够会在口试中遇到。 我会查阅一些材料并能够加上本身的明白,来纪录这些题目。更多文章请前去我的个人博客

这个题目是有关实行递次和Event Loop的。关于Event Loop和使命行列等观点,能够先浏览我援用中的文章,本文重要剖析一些存在的迷惑点。

下面这个例子比较典范:

setImmediate(function(){
    console.log(1);
},0);
setTimeout(function(){
    console.log(2);
},0);
new Promise(function(resolve){
    console.log(3);
    resolve();
    console.log(4);
}).then(function(){
    console.log(5);
});
console.log(6);
process.nextTick(function(){
    console.log(7);
});
console.log(8);

//输出效果是3 4 6 8 7 5 2 1

在诠释输出效果之前,我们来看几个观点:

macro-task: script (团体代码),setTimeout, setInterval, setImmediate, I/O, UI rendering.
micro-task: process.nextTick, Promise(原生),Object.observe,MutationObserver

除了script团体代码,micro-task的使命优先级高于macro-task的使命优先级。
个中,script(团体代码) ,能够明白为待实行的一切代码。

所以实行递次以下:

第一步. script团体代码被实行,实行历程为

  • 建立setImmediate macro-task

  • 建立setTimeout macro-task

  • 建立micro-task Promise.then 的回调,并实行script console.log(3); resolve(); console.log(4); 此时输出3和4,虽然resolve调用了,实行了然则团体代码还没实行完,没法进入Promise.then 流程。

  • console.log(6)输出6

  • process.nextTick 建立micro-task

  • console.log(8) 输出8

第一个历程事后,已输出了3 4 6 8

第二步. 由于其他micro-task 的 优先级高于macro-task。
此时micro-task 中有两个使命根据优先级process.nextTick 高于 Promise。
所以先输出7,再输出5

第三步,micro-task 使命列表已实行终了,家下来实行macro-task. 由于setTimeout的优先级高于setIImmediate,所以先输出2,再输出1。

全部历程形貌起来像是同步操作,实际上是基于Event Loop的事宜轮回。

关于micro-task和macro-task的实行递次,可看下面这个例子(来自《深入浅出Node.js》):

//到场两个nextTick的回调函数
process.nextTick(function () {
    console.log('nextTick耽误实行1');
});
process.nextTick(function () { 
    console.log('nextTick耽误实行2');
});
// 到场两个setImmediate()的回调函数
setImmediate(function () {
    console.log('setImmediate耽误实行1'); 
    // 进入下次轮回 
    process.nextTick(function () {
        console.log('强势插进去');
    });
});
setImmediate(function () {
    console.log('setImmediate耽误实行2'); 
});

console.log('一般实行');

书中给出的实行效果是:

一般实行
nextTick耽误实行1
nextTick耽误实行2
setImmediate耽误实行1
强势插进去
setImmediate耽误实行2

process.nextTick在两个setImmediate之间强行插进去了。
但运转这段代码发明效果倒是如许:

一般实行
nextTick耽误实行1
nextTick耽误实行2
setImmediate耽误实行1
setImmediate耽误实行2
强势插进去

朴先生写那本书的时刻,node最新版本为0.10.13,而我的版本是6.x

老版本的Node会优先实行process.nextTick。
当process.nextTick行列实行完后再实行一个setImmediate使命。然后再次回到新的事宜轮回。所以实行完第一个setImmediate后,行列里只剩下第一个setImmediate里的process.nextTick和第二个setImmediate。所以process.nextTick会先实行。

而在新版的Node中,process.nextTick实行完后,会轮回遍历setImmediate,将setImmediate都实行终了后再跳出轮回。所以两个setImmediate实行完后行列里只剩下第一个setImmediate里的process.nextTick。末了输出”强势插进去”。

详细完成可参考Node.js源码

关于优先级的另一个比较清楚的版本:

观察者优先级

在每次轮训搜检中,各观察者的优先级分别是:

idle观察者 > I/O观察者 > check观察者。

idle观察者:process.nextTick

I/O观察者:平常性的I/O回调,如收集,文件,数据库I/O等

check观察者:setImmediate,setTimeout

setImmediate 和 setTimeout 的优先级

看下面这个例子:

setImmediate(function () {
    console.log('1'); 
});
setTimeout(function () {
    console.log('2'); 
}, 0);

console.log('3');

//输出效果是3 2 1

我们晓得如今HTML5划定setTimeout的最小间隔时候是4ms,也就是说0实际上也会别默认设置为最小值4ms。我们把这个耽误加大

上面说到setTimeout 的优先级比 setImmediate的高,实在这类说法是有条件的。

再看下面这个例子,为setTimeout增加了一个耽误20ms的时候:

setImmediate(function () {
    console.log('1'); 
});
setTimeout(function () {
    console.log('2'); 
}, 20);

console.log('3');

//输出效果是3 2 1

setTimeout耽误20ms再实行,而setImmediate是马上实行,居然2比1还先输出??

尝尝打印出这个顺序的实行时候:

var t1 = +new Date();
setImmediate(function () {
    console.log('1'); 
});
setTimeout(function () {
    console.log('2'); 
},20);

console.log('3');
var t2 = +new Date();
console.log('time: ' + (t2 - t1));
//输出
3 
time: 23 
2 
1

顺序实行用了23ms, 也就是说,在script(团体代码)实行完之前,setTimeout已过期了,所以当进入macro-task的时刻setTimeout依旧优先于setImmediate实行。假如我们把这个值调大一点呢?

var t1 = +new Date();
setImmediate(function () {
    console.log('1'); 
});
setTimeout(function () {
    console.log('2'); 
},30);

console.log('3');
var t2 = +new Date();
console.log('time: ' + (t2 - t1));
//输出
3 
time: 23 
1 
2

setImmediate早于setTimeout实行了,由于进入macro-task 轮回的时刻,setTimeout的定时器还没到。

以上试验是基于6.6.0版本Node.js测试,实际上在遇到相似这类题目的时刻,最好的方法是参考规范,并查阅源码,不能死记观点和递次,由于规范也是会变的。包含此文也是自学总结,经供参考。

参考:
https://www.zhihu.com/questio…
https://segmentfault.com/a/11…
http://www.jianshu.com/p/837b…

    原文作者:fwon
    原文地址: https://segmentfault.com/a/1190000008595101
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞