秋招落幕,回顾大厂的前端面试,JS事件循环几乎是必考题——不仅是简单问概念,而是扔给一段代码让你写输出顺序,错一个步骤就可能错失offer。
一、我踩过的3个误区
1. 把“await后面的代码”当成同步
await本质是Promise.then的语法糖,后续代码是微任务,同步代码执行完成前,要把它放进微任务队列。
2. 漏看“Promise构造函数内的同步代码”
看到new Promise(...)就默认是异步,忽略了构造函数里的代码会同步执行(只有.then/.catch是微任务)。
3. 误以为“宏任务队列会一次性清空”
事件循环的核心规则里,微任务是“一次性清空”,但宏任务是“一次只执行一个”,执行完还要回头清微任务。
二、做题方法
一般这种输出题就是五分钟,并且要说出完整的执行流程。
步骤1:从上到下扫代码
从上到下逐行扫代码,区分“同步/微任务/宏任务”:
| 类型 | 包含内容(高频考点) |
|---|---|
| 同步代码 | 1. 普通console.log2. 函数调用(如 async1())3. Promise构造函数内的代码await`前面的代码 |
| 微任务 | 1. Promise.then/.catch/.finally2. await后面的代码(等价then回调 |
| 宏任务 | 1. setTimeout/setInterval |
步骤2:执行同步代码——按顺序记输出
-
同步代码按“从上到下”执行,函数调用也是同步代码;
-
遇到异步代码时,不执行回调,放进微任务/宏任务队列:
-
把同步代码的输出按顺序写下来,这是后续步骤的基础。
步骤3:清队列——先微后宏,按规则来
- 清微任务队列
- 执行1个宏任务
- 循环:执行完1个宏任务后,回到“清微任务队列”步骤,直到所有队列都空。
真题1:小米一面——基础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');
setTimeout(() => {
console.log('setTimeout');
}, 0);
async1();
new Promise((resolve) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise2');
});
console.log('script end');
答案
//script start
//async1 start
//async2
//promise1
//script end
//async1 end
//promise2
//setTimeout
真题2:携程一面
题目代码
async function async1() {
console.log("A");
await async2();
console.log("B");
}
async function async2() {
console.log("C");
}
console.log("D");
async1();
new Promise(resolve => {
console.log("E");
resolve();
}).then(() => {
console.log("F");
});
console.log("G");
答案:
//D A C E G B F
真题3:金山云一面
let promise1 = new Promise(function (resolve) {
console.log("promise1");
resolve();
console.log("promise1 end");
}).then(function () {
console.log("promise2");
});
console.log("script start");
Promise.resolve().then(() => {
console.log("promise then1");
setTimeout(() => {
console.log("promise then1 setTimeout");
}, 0);
});
setTimeout(function () {
console.log("settimeout");
}, 0);
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
async1();
console.log("script end");
答案
//promise1
// promise1 end
// script start
// async1 start
// async2
// script end
// promise2
// promise then1
// async1 end
// settimeout
// promise then1 setTimeout