相信很多小伙伴看面试题的时候都看到过这种问js执行顺序的问题,这个问题也困扰了我一段时间,以下是我看完几篇大佬的文章后的理解,希望对大家有帮助。
首先,你要知道javascript是单线程语言,js任务需要排队顺序执行,如果一个任务耗时过长,后边一个任务也的等着,为了解决这种情况,将任务分为了同步任务和异步任务;而异步任务又可以分为微任务和宏任务。
宏任务包括有:script( 整体代码),setTimeout,setInterval 等
微任务包括有:Promise.then,process.nextTick 等
代码示例:
话不多说,直接上代码,你能正确判断出输出顺序吗!
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');
解析:
- 整体 script 作为第一个宏任务进入主线程,遇到 console.log,输出 script start
- 遇到 setTimeout,其回调函数被分发到 宏任务 中
- 遇到 Promise,Promise里的代码立即执行,输出 promise1,将其 then函数分到到 微任务 中
- 遇到 console.log,输出 script end
- 主线程中任务执行完后,就要执行分发到微任务中代码(存在微任务的话,那么就执行所有的微任务),输出 promise2
- 微任务执行完后再看下一个宏任务 setTimeout ,输出 setTimeout
结合图片哈,更容易理解!
so,你猜对了没,再看一个复杂点的例子哈;
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
接着来解析
- 整体 script 作为第一个宏任务进入主线程,遇到 console.log,输出 1
- 遇到 setTimeout,其回调函数被分发到 宏任务 中,记住 setTimeout - 1
- 遇到 process.nextTick,其回调函数被分发到 微任务 中
- 遇到 Promise,Promise里的代码立即执行,输出 7,将其 then函数分到到 微任务 中
- 遇到 setTimeout ,其回调函数被分发到 宏任务 中,记住 setTimeout - 2
- 主线程中任务执行完后,就要执行分发到微任务中代码,此时微任务中有第 3 步的 process.nextTick 和第 4 步的 Promise.then 方法,按顺序执行输出 6,8
- 微任务执行完后再看下一个宏任务 setTimeout - 1 ,遇到 console.log,输出 2
- 遇到 setTimeout - 1 中的 process.nextTick ,其回调函数被分发到 微任务 中
- 遇到 setTimeout - 1 中 Promise,Promise里的代码立即执行,输出 4,将其 then函数分到到 微任务 中
- 执行完这些任务后,再来执行分发到微任务中代码,此时微任务中有第 8 步的 process.nextTick 和第 9 步的 Promise.then 方法,按顺序执行输出 3,5
- 微任务执行完后再看下一个宏任务 setTimeout - 2 ,遇到 console.log,输出 9
- 遇到 setTimeout - 2 中的 process.nextTick ,其回调函数被分发到 微任务 中
- 遇到 setTimeout - 2 中的 Promise,Promise里的代码立即执行,输出 11,将其 then函数分到到 微任务 中
- 执行完这些任务后,再来执行分发到微任务中代码,此时微任务中有第 12步的 process.nextTick 和第 13 步的 Promise.then 方法,按顺序执行输出 10,12
所以,输出顺序应该是 1,7,6,8,2,4,3,5,9,11,10,12
总结:
主线程中任务执行完后,就要执行分发到微任务中代码,存在微任务的话,那么就执行所有的微任务,当前所有的微任务执行完再进入新的宏任务中执行宏任务中的代码,如果有微任务就分配到微任务的队列中,当前宏任务中的代码执行完后,再接着执行所有的微任务,然后再进入下一个宏任务…以此类推下去!