先来一个简单的题目热热身
以下代码的打印顺序是什么?
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');
这里涉及到js事件循环机制的问题,同步任务都在主线程上执行,形成一个执行栈。程序会先读取并执行主线程(script)的代码,而这里的Promise和setTimeout就属于异步任务,所以会先打印“script start” 以及 “script end”。
主线程之外,还存在一个任务队列。只要异步任务有了运行结果,就在任务队列中放置一个事件。一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,将队列中的事件放到执行栈中依次执行。
而Promise属于微任务,setTimeout属于宏任务。在读取script的过程中,Promise内的回调会被安排到Microtasks(微任务执行栈)中,而setTimeout内的回调则被安排到下一个宏任务中去了。
所以最后的执行顺序为:script start、sctipt end、promise1、promise2、setTimeout
加入async后
async function async1() {
console.log(1);
const result = await async2();
console.log(3);
}
async function async2() {
console.log(2);
}
Promise.resolve().then(() => {
console.log(4);
});
setTimeout(() => {
console.log(5);
});
async1();
console.log(6);
答案是【1,2,6,4,3,5】。JS的事件循环中每个宏任务称为一个Tick(标记),在每个标记的末尾会追加一个微任务队列,一个宏任务执行完后悔执行所有的微任务,直到清空队列。async1函数本身会返回一个Promise,同时await后面紧跟着async2函数返回的Promise,console.log(3)其实是在async2函数返回的Promise的then语句中执行的,then语句本身也会返回一个Promise然后追加到微任务队列中,所以在微任务队列中 console.log(3) 在 console.log(4)后面。