从promise、process.nextTick、setTimeout动身,谈谈Event Loop中的Job queue

在原文的基础上加了一点参考资料

题目的引出

event loop都不生疏,是指主线程从“使命行列”中轮回读取使命,比方

例1:

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

console.log(2)

//输出2,1

在上述的例子中,我们邃晓起首实行主线程中的同步使命,当主线程使命实行终了后,再从event loop中读取使命,因而先输出2,再输出1。

event loop读取使命的先后递次,取决于使命行列(Job queue)中关于差别使命读取划定规矩的限制。比方下面一个例子:

例2:

setTimeout(function () {
  console.log(3);
}, 0);

Promise.resolve().then(function () {
  console.log(2);
});
console.log(1);
//输出为  1  2 3

先输出1,没有题目,由于是同步使命在主线程中优先实行,这里的题目是setTimeout和Promise.then使命的实行优先级是怎样定义的。

2 . Job queue中的实行递次
在Job queue中的行列分为两种范例:macro-task和microTask。我们举例来看实行递次的划定,我们设

macro-task行列包含使命: a1, a2 , a3
micro-task行列包含使命: b1, b2 , b3

实行递次为,起首实行marco-task行列开首的使命,也就是 a1 使命,实行终了后,在实行micro-task行列里的一切使命,也就是顺次实行b1, b2 , b3,实行完后清空micro-task中的使命,接着实行marco-task中的第二个使命,顺次轮回。

相识完了macro-task和micro-task两种行列的实行递次以后,我们接着来看,实在场景下这两种范例的行列里真正包含的使命(我们以node V8引擎为例),在node V8中,这两种范例的实在使命递次以下所示:

macro-task行列实在包含使命:

script(主程序代码),setTimeout, setInterval, setImmediate, I/O, UI rendering

micro-task行列实在包含使命:
process.nextTick, Promises, Object.observe, MutationObserver

由此我们获得的实行递次应该为:

script(主程序代码)—>process.nextTick—>Promises…——>setTimeout——>setInterval——>setImmediate——> I/O——>UI rendering

在ES6中macro-task行列又称为ScriptJobs,而micro-task又称PromiseJobs

3 . 实在环境中实行递次的举例
(1) setTimeout和promise
例3:

setTimeout(function () {
console.log(3);
}, 0);

Promise.resolve().then(function () {
console.log(2);
});

console.log(1);

我们先以第1小节的例子为例,这里遵照的递次为:

script(主程序代码)——>promise——>setTimeout
对应的输出顺次为:1 ——>2————>3

(2) process.nextTick和promise、setTimeout
例子4:

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

new Promise(function(resolve,reject){
   console.log(2);
   resolve();
}).then(function(){console.log(3)
}).then(function(){console.log(4)});

process.nextTick(function(){console.log(5)});

console.log(6);
//输出2,6,5,3,4,1

这个例子就比较庞杂了,这里要注意的一点在定义promise的时刻,promise组织部份是同步实行的,如许题目就水到渠成了。

起首剖析Job queue的实行递次:

script(主程序代码)——>process.nextTick——>promise——>setTimeout

I) 主体部份: 定义promise的组织部份是同步的,
因而先输出2 ,主体部份再输出6(同步状况下,就是严厉根据定义的先后递次)

II)process.nextTick: 输出5

III)promise: 这里的promise部份,严厉的说实际上是promise.then部份,输出的是3,4

IV) setTimeout : 末了输出1

综合的实行递次就是: 2——>6——>5——>3——>4——>1

(3)更庞杂的例子

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

new Promise(function(resolve,reject){
   console.log(2);
   setTimeout(function(){resolve()},0)
}).then(function(){console.log(3)
}).then(function(){console.log(4)});

process.nextTick(function(){console.log(5)});

console.log(6);

//输出的是  2 6 5 1 3 4

这类状况跟我们(2)中的例子,区分在于promise的组织中,没有同步的resolve,因而promise.then在当前的实行行列中是不存在的,只要promise从pending转移到resolve,才会有then要领,而这个resolve是在一个setTimout时间中完成的,因而3,4末了输出。

知识点参考

  1. process.nextTick(callback)

    process.nextTick()要领将 callback 添加到”next tick 行列”。 一旦当前事宜轮询行列的使命悉数完成,在next tick行列中的一切callbacks会被顺次挪用。

    这类体式格局不是setTimeout(fn, 0)的别号。它越发有效率。事宜轮询随后的ticks 挪用,会在任何I/O事宜(包含定时器)之前运转。

    每次事宜轮询后,在分外的I/O实行前,next tick行列都邑优先实行。 递归挪用nextTick callbacks 会壅塞任何I/O操纵,就像一个while(true) 轮回一样。

  function definitelyAsync(arg, cb) {
  if (arg) {
    process.nextTick(cb);
    return;
  }

  fs.stat('file', cb);  //触及io操纵
}
//这里process.nextTick就会壅塞io操纵
    原文作者:嗯呵吱吱吱
    原文地址: https://segmentfault.com/a/1190000015891460
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞