一、问题的引出
例1:
setTimeout(
function(){
console.log(1);
}
},0);
console.log(2);
//输出2,1
在上述例子中首先执行主线程中的同步任务,当主线程任务执行完毕后,再从event loop中读取任务,因此先输出2,再输出1。
例2:
setTimeout(function () {
console.log(3);
}, 0);
Promise.resolve().then(function () {
console.log(2);
});
console.log(1);
//输出为 1 2 3
先输出1,是因为同步任务在主线程中优先执行,但这里的问题是setTimeout和Promise.then任务的执行优先级是如何定义的。
二、Job queue中的执行顺序
举例来看执行顺序的规定,设:
macro-task队列包含任务: a1, a2 , a3
micro-task队列包含任务: b1, b2 , b3
执行顺序为:首先执行marco-task队列开头的任务,也就是 a1 任务,执行完毕后,在执行micro-task队列里的所有任务,也就是依次执行b1, b2 , b3,执行完后清空micro-task中的任务,接着执行marco-task中的第二个任务,依次循环。
在node V8中,这两种类型的真实任务顺序如下所示:
script(主程序代码),setTimeout, setInterval, setImmediate, I/O, UI rendering
process.nextTick, Promises, Object.observe, MutationObserver
script(主程序代码)—>process.nextTick—>Promises...——>setTimeout——>setInterval——>setImmediate——> I/O——>UI rendering
三、 真实环境中执行顺序的举例
例3:setTimeout和promise
setTimeout(function () {
console.log(3);
}, 0);
Promise.resolve().then(function () {
console.log(2);
});
console.log(1);
先以第1小节的例子为例,这里遵循的顺序为:
script(主程序代码)——>promise——>setTimeout
对应的输出依次为:1 ——>2——>3
例4:process.nextTick和promise、setTimeout
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
例5:更复杂的例子
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
例5与例4的区别在于promise的构造中,没有同步的resolve,因此promise.then在当前的执行队列中是不存在的,只有promise从pending转移到resolve,才会有then方法,而这个resolve是在一个setTimout时间中完成的,因此3,4最后输出。