先来看一道经典面试题

//请写出输出内容
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');

/*
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
*/

为了知道这道题的答案,必须理解下面的原理

ES6标准中任务队列存在两种类型:

宏观任务(marcotask):

  • setTimeout,setInterval
  • requestAnimationFrame
  • 解析HTML
  • 执行主线程js代码
  • 修改url
  • 页面加载
  • 用户交互

微观任务(mircotask):

  • promise
  • mutation.oberver
  • process.nextTick

再来是任务栈调用任务队列的原则

  • 读取所有微观任务队列 -> 执行 ->
  • 读取一个宏观任务队列 -> 执行 ->
  • 读取所有微观任务队列 -> 执行 ->
  • 再读取一个宏观任务队列…的顺序。

总结

  1. 任务队列不止有一个,他们被分为两大类,即宏观任务和微观任务
  2. promise和setTimeout相比,setTimeout会在promise函数之后执行
  3. promise函数内是同步的,resolve才是异步的
  4. async函数内,await是同步的,会立即执行,但是await之后的部分会变为异步的

搞明白这几点,这道题就解决了