这是一个非常经典的问题,很多人对 async/await 的“异步”机制存在误解。我们分两部分来回答:
1. async 代码是异步执行的吗?
结论:是的,但它是通过“非阻塞”的方式执行的。
当你调用一个 async 函数时:
- 函数体内部的执行顺序: 在你遇到第一个
await之前,代码是同步执行的。 - 遇到
await之后:await后面的表达式会立即执行。- 一旦执行到
await,函数会被“挂起”(暂停)。 - JS 引擎会跳出这个
async函数,去执行该函数外部的代码(这就是异步的体现)。 - 等到
await后面的异步操作(Promise)完成,JS 引擎再回到这个async函数中,恢复执行后面的代码。
2. 后面的方法会受影响吗?
这取决于你指的“后面”是什么:
情况 A:async 函数体内部“后面”的代码
受影响。
它们必须等待 await 这一行执行完成并拿到结果后,才会继续执行。这就像是“人为地把异步代码拉直成同步顺序”。
async function test() {
console.log("1");
await new Promise(r => setTimeout(r, 1000)); // 暂停 1 秒
console.log("2"); // 这一行会被阻塞,直到 1 秒后才会执行
}
console.log("3");
test();
console.log("4");
// 执行顺序:1 -> 3 -> 4 -> (等待1秒) -> 2
情况 B:async 函数调用后的外部代码
不受影响(主线程不会被阻塞)。
这是 async/await 最核心的优势。虽然 async 函数内部被“暂停”了,但它不会阻塞整个 JavaScript 的执行线程。
在上面的例子中,当 test() 执行到 await 暂停时,主线程立刻跳出 test 函数,继续去执行后面的 console.log("4")。
总结:关键点对比
为了让你彻底明白,请记住这两个对比:
-
对于
async函数内部:await像是一道“锁”,它强迫后面的代码必须等待前面的异步操作完成。这让复杂的异步逻辑(如:先查数据库,再查缓存,最后返回数据)写起来像写同步代码一样简单。 -
对于整个程序:
async/await是非阻塞的。即使你在函数里写了await等待 10 秒,页面也不会卡死,其他的逻辑(如点击事件、动画、其他网络请求)依然可以正常运行。
一句话总结:
async/await 只是在当前函数内部让代码看起来像同步,但在宏观上,它依然是异步的,不会阻塞主线程,也不会影响外部代码的正常执行。