话不多说,先上面试题
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end')
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');
分析Eevent-Loop的问题时,我们将代码分成三块:同步代码,微任务队列,宏任务队列,所以从上到下:
- 同步代码:['script start', 'async1 start', 'async2', 'promise1', 'script end']
- 微任务:['async1 end', 'promise2']
- 宏任务:['setTimeout']
将输出结果依次从队列中取出:'script start', 'async1 start', 'async2', 'promise1', 'script end','async1 end', 'promise2','setTimeout'

难点
此问题的难点在于async和await, 那我们就来单独分析它
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end')
}
async function async2() {
console.log('async2');
}
console.log('script start');
async1();
// 同Generate函数一样,async函数返回一个Promise对象,可以使用then方法添加回调函数。
// 当函数执行时,一旦遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。
// 所以上面await async2()代码等价于
async function async1() {
Promise.resolve(async2()).then(() => {
console.log('async1 end');
});
}
浏览器事件环

- 首先执行同步代码,这属于宏任务(script,ui渲染属于宏任务)
- 当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
- 执行所有微任务
- 当执行完所有微任务后,如有必要会渲染页面
- 然后开始下一轮 Event Loop,执行宏任务中的异步代码