async/await
不是同步代码,它只是让异步代码的写法看起来像同步代码,但底层仍然是异步执行的。以下是详细解析:
一、async/await 的异步本质
1. 语法糖的假象
async/await
是 Promise 的语法糖,目的是简化异步代码的编写。- 代码的书写形式看似同步,但执行过程仍然是异步非阻塞的。
2. 代码示例对比
// 同步代码:按顺序执行,会阻塞后续代码
function syncFunc() {
const result = doSomething(); // 阻塞直到完成
console.log(result);
}
// async/await:看似同步,实际异步
async function asyncFunc() {
const result = await doSomethingAsync(); // 不阻塞主线程
console.log(result);
}
二、async/await 的执行机制
1. 执行流程
- 遇到
await
:暂停当前async
函数的执行,交出主线程控制权。 - Promise 解决后:将后续代码包装为微任务,加入微任务队列。
- 事件循环:继续执行其他同步代码,待调用栈清空后,执行微任务。
2. 执行过程图解
console.log("Start");
async function demo() {
console.log("Before await");
await Promise.resolve(); // 暂停,后续代码变为微任务
console.log("After await");
}
demo();
console.log("End");
// 输出顺序:
// Start → Before await → End → After await
三、与同步代码的核心区别
特性 | 同步代码 | async/await |
---|---|---|
阻塞性 | 阻塞后续代码执行 | 非阻塞,交出主线程控制权 |
执行线程 | 在主线程顺序执行 | 主线程空闲后执行微任务 |
适用场景 | 简单计算、快速操作 | I/O 操作、网络请求等异步任务 |
四、常见误区
1. 误以为 await
会阻塞主线程
- 真相:
await
只会暂停当前async
函数内的代码,主线程仍可执行其他任务。
async function test() {
await longTask(); // 假设 longTask 耗时 2 秒
console.log("Done");
}
test();
console.log("主线程继续执行"); // 会立即输出,无需等待 2 秒
2. 在循环中错误使用串行化
// ❌ 低效:逐个等待,总耗时 = 每次迭代耗时之和
for (const url of urls) {
await fetch(url);
}
// ✅ 高效:并行执行
await Promise.all(urls.map(url => fetch(url)));
五、总结
async/await
不是同步代码,而是异步代码的语法糖。- 它的核心价值是让异步代码更易读、易维护,但不会改变 JavaScript 单线程和非阻塞的本质。
- 关键特性:
await
会暂停当前函数,但不阻塞主线程。- 底层依赖 Promise 和微任务队列。
- 错误需用
try/catch
捕获(或.catch()
)。