async/await 适合线性依赖流程,Promise.all 更适配并行无依赖操作,复杂场景应混合使用;超时和取消需手动处理,不可仅依赖语法糖。

async/await 和 Promise 链不是非此即彼的选择,而是互补的工具。关键不在“哪个更好”,而在“哪个更合适”——取决于流程结构、错误处理粒度和并发控制需求。
线性依赖流程,优先用 async/await
当后一步必须等前一步结果才能执行(比如登录 → 拿 token → 请求用户信息 → 加载权限),async/await 的顺序书写天然匹配逻辑流,避免 .then() 层层嵌套带来的缩进混乱和变量传递麻烦。
- 每个 await 表达式单独一行,语义清晰,调试时可直接在某行加断点观察中间值
- 条件分支(如 if (user.isAdmin) await loadAdminPanel())写起来自然,不用拆成多个 .then 链或嵌套 resolve
- try/catch 能统一捕获整个流程中的任意 reject,比在每个 .then 后补 .catch 更简洁可靠
并行无依赖操作,回归 Promise.all
多个请求彼此独立、无需等待对方结果(比如同时拉取用户资料、通知列表、未读消息数),硬用 async/await 会变成串行,白白拖慢整体耗时。
- Promise.all([fetchUser(), fetchNotices(), fetchUnreads()]) 一次性发起,全部成功才进入下一步
- 若需容忍部分失败,改用 Promise.allSettled(),再遍历结果判断 status 字段
- 避免写成 await fetchUser(); await fetchNotices(); await fetchUnreads() —— 这是常见但低效的误用
复杂组合逻辑,混合使用更灵活
真实业务中,往往是“部分并行 + 部分串行 + 条件分支”的混合体。这时不必强求统一风格,按模块职责选择即可。
立即学习“Java免费学习笔记(深入)”;
- 先并行拉基础数据:const [user, config] = await Promise.all([fetchUser(), fetchConfig()])
- 再根据 user.role 决定是否串行加载权限:if (user.role === 'admin') await loadPermissions()
- 最后并行渲染多个区块:await Promise.all([renderProfile(user), renderDashboard(config)])
错误处理与边界情况不能只靠语法糖
async/await 看似简化了错误处理,但容易掩盖两类问题:网络中断、请求取消、超时控制。
- await 本身不提供超时机制,需手动包装:Promise.race([fetch(...), new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 5000))])
- 要中止进行中的请求,必须配合 AbortController,而不是仅靠 try/catch
- Promise 链中 .catch() 可以精确控制某一步失败后的降级行为(如 fallback 到缓存),而顶层 try/catch 有时粒度太粗



















