async/await 不阻塞主线程,仅暂停当前 async 函数执行;应优先并发请求(promise.all)、避免串行 await,并区分“函数暂停”与“线程阻塞”。

async/await 本身不会阻塞整个 JavaScript 主线程,但它会让当前 async 函数内部的后续语句暂停执行,直到 await 的 Promise 被 resolve。所谓“不必要的阻塞”,通常是指本可并发执行的异步任务被写成了串行等待,拖慢整体响应速度。关键不是去掉 await,而是合理安排执行时机。
避免串行等待无关任务
多个独立请求(如获取用户信息、配置、公告)若逐个 await,会变成耗时叠加。应先发起全部请求,再统一等待结果。
- ❌ 错误写法(串行,总耗时 ≈ t₁ + t₂ + t₃):
const user = await fetchUser();<br>const config = await fetchConfig();<br>const notice = await fetchNotice();
- ✅ 正确写法(并发,总耗时 ≈ max(t₁, t₂, t₃)):
const [user, config, notice] = await Promise.all([<br> fetchUser(),<br> fetchConfig(),<br> fetchNotice()<br>]);
不 await 时也能调用异步函数
如果某个异步操作无需等待其完成就可继续执行后续逻辑(比如上报日志、预加载资源),直接调用即可,不必加 await。
- 例如:
console.log('开始操作');<br>trackEvent('page_view'); // 不 await,立即返回 Promise,不卡住下面代码<br>console.log('操作已触发,继续执行'); - 注意:若需处理错误,可用
.catch()单独捕获,避免影响主流程。
区分“暂停函数”和“阻塞线程”
await 只暂停它所在的 async 函数,不会冻结浏览器或 Node.js 的事件循环。其他同步代码、定时器、事件监听器照常运行。
- 比如:
async function loadA() { await delay(2000); console.log('A done'); }<br>function loadB() { console.log('B start'); setTimeout(() => console.log('B done'), 1000); }<br>loadA();<br>loadB();
输出顺序是:B start → A done → B done,说明 loadB 完全没被 await 阻塞。 - 本质是:await 把函数剩余部分包装进微任务队列,控制权立刻交还给事件循环。
慎用顶层 await 或嵌套 await
在模块顶层或复杂条件分支中滥用 await,容易隐式拉长初始化时间或造成不可预期的等待链。
- 避免在非必要位置使用顶层 await(如配置加载后才渲染页面),可改用动态 import 或显式 loading 状态。
- 嵌套 await(如循环内 await)默认是串行的,如需并发,改用
Promise.all([...].map(...))。 - 对可能失败但不影响主流程的操作,用
try/catch包裹单个 await,而不是让整个函数因一处失败而中断。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











