(注:图片来自https://juejin.im/post/5d5b4c2df265da03dd3d73e5#heading-5)
JavaScript是单线程的,所以在同一时刻只能做一件事,为了防止页面中有某些耗时的任务执行时间过长造成页面假死,js把任务的执行模式划分成了两种,分别是同步模式和异步模式。异步模式包含宏任务和微任务。
宏任务的优先级为:setTimeout>setInterVal>setImmediate>I/O
微任务的优先级为:promise.nextTick>promise>MutationObserver
执行顺序的规则:
首先JavaScript代码从上至下遇到定时器等宏任务会加入到宏任务队列,遇到promise.then等微任务会加入到微任务队列。等到主执行栈的同步代码执行完毕,会清空微任务队列,先加入的先执行后加入的后执行。清空微任务队列后去检查宏任务队列,每次只取出一个宏任务执行,执行完毕再次清空微任务队列,清空完毕再去检查宏任务队列。
下面举例讲解:
console.log('global');
setTimeout(function() {
console.log('setTimeout1');
new Promise(function(resolve) {
console.log('setTimeout1_promise');
resolve();
}).then(function() {
console.log('setTimeout1_promiseThen')
})
process.nextTick(function() {
console.log('setTimeout1_nextTick');
})
},0);
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promiseThen1');
})
setImmediate(function() {
console.log('setImmediate1');
setTimeout(function(){
console.log("last")
},0);
setImmediate(function() {
console.log('setImmediate3');
})
})
setImmediate(function() {
console.log('setImmediate2');
})
process.nextTick(function() {
console.log('nextTick');
})
new Promise(function(resolve) {
console.log('promise2');
resolve();
}).then(function() {
console.log('promiseThen2')
})
setTimeout(function() {
console.log('setTimeout2');
},0)
1. 首先执行整体代码,输出global;
2. 遇到setTimeout任务,将其加入到宏任务,此时
宏任务为:setTimeout1
微任务为空
3. 遇到promise,输出promise1,将其异步方法放入微任务中,此时
宏任务为:setTimeout1
微任务为:promise1
4. 遇到setImmediate,放入宏任务中,此时
宏任务为:setTimeout1
setImmediate1,setImmediate2
微任务为:promise1
5. 遇到promise.nextTick,放入微任务队列,此时
宏任务为:setTimeout1
setImmediate1,setImmediate2
微任务为:promise1
nextTick1
6. 遇到promise,输出promise2,将其异步回调放入微任务中,此时
宏任务为:setTimeout1
setImmediate1,setImmediate2
微任务为:promise1,promise2
nextTick1
7. 遇到setTimeout,放入宏任务中,此时
宏任务为:setTimeout1,setTimeout2
setImmediate1,setImmediate2
微任务为:promise1,promise2
nextTick1
第一轮循环结束。
第二轮循环:
1. 先执行微任务,nextTick优先级高,输出nextTick;
2. 按队列先进先出,promise1的then执行,输出promiseThen1;
3. promise2的then执行,输出promiseThen2;
4. 微任务结束,开始执行宏任务,遇到setImmediate,将其加入下一轮循环;
5. 执行setTimeout1,输出setTimeout1,遇到setTimeout1_promise,输出setTimeout1_promise,将其异步加入到微任务,此时:
宏任务:
setImmediate1,setImmediate2
微任务:
setTimeout1_promise
6. 遇到process.nextTick,加入微任务,此时:
宏任务:
setImmediate1,setImmediate2
微任务:
setTimeout1_promise
setTimeout1_nextTick
7. 执行setTimeout2的任务,输出setTimeout2。
本轮结束,进入下一轮循环。
1. 执行微任务,nextTick>promise,输出setTimeout1_nextTick;
2. 执行setTimeout_promise的then回调,输出setTimeout1_promiseThen;
3. 执行setImmediate1,输出setImmediate1,遇到setTimeout和setImmediate,加入宏任务中;
4. 执行setImmediate2,输出setImmediate2
本轮结束
1. setTimeout和setImmediate都在setImmediate中,执行顺序不定,所以last和setImmediate3顺序不定,最后的输出为: