⭐ 推荐:社区规则条款 V1.0

js async await 和 Promise 区别

萝卜特棒
萝卜特棒 正式会员萌新站长
发布于 2026-10-17 07:52 ·3 浏览 ·0 回复
内容摘要

async/await 是 Promise 的语法糖而非替代品:Promise 是异步的能力与规范,async 函数永远返回 Promise,await 通过微任务挂起并恢复执行,错误处理 try/catch 与 .catch() 等价但可

async/await 不是 Promise 的替代品,它是 Promise 的语法糖——底层依然是 Promise 和微任务,只是把 .then() 链换成了看起来像同步代码的写法。结论:Promise 是异步的“能力”和“规范”,async/await 是使用这套能力的“语法”;所有 async 函数都返回 Promise,但用 await 写出来的代码更接近人脑的阅读顺序。

async/await 和 Promise 有什么区别?

核心区别只有一句话:Promise 解决的是“回调地狱”,async/await 解决的是“then 链地狱”。

Promise 是 ES6(2015)引入的对象,表示一个将来才会知道结果的操作,有三种状态:pending(进行中)、fulfilled(成功)、rejected(失败),状态一旦改变不可逆。它靠 .then() / .catch() / .finally() 注册回调。

async/await 是 ES2017 引入的语法,async 用来标记一个函数会返回 Promise,await 用来暂停函数执行、等待 Promise 落定并取出结果。结论:await 只能在 async 函数内部(或 ES2022 的模块顶层)使用,而 Promise 在普通函数里就能写。

async 函数返回的是什么?

结论:async 函数永远返回一个 Promise,哪怕你写 return 1。

async function f() { return 1 }
f() // Promise {<fulfilled>: 1}

三点要注意:

  1. 函数体内 return x 等价于 return Promise.resolve(x);如果 return 的本身是 Promise,会被“解包”,最终 resolve 它的结果。
  2. 函数体内抛错(throw new Error())等价于返回一个 rejected 的 Promise,不是同步抛出。
  3. 关键细节:async function f(){} 调用时,函数体是同步执行的,一直跑到第一个 await 才交出控制权。所以 f() 前面那段代码不会异步。

await 是怎么把异步代码变同步的?

结论:await 没让代码变同步,它只是把 await 后面的代码塞进了微任务队列。

await p 的执行过程是:p 不是 thenable 就直接取值;是 thenable 就调用它的 then,把当前 async 函数挂起,等 p 落定后,再把剩余代码作为微任务继续执行。

这带来两个可验证的后果:一是 await 一次至少多走一轮微任务,比写 .then() 慢一点点(量级在微秒,正常业务可以忽略);二是 await 后面的 console.log 一定晚于同层的同步代码,和 .then() 的回调顺序一致。

错误处理该用 try/catch 还是 .catch()?

结论:两者等价,但 try/catch 能覆盖同一个代码块里的多个 await。

// Promise 写法
fetchUser().then(u => fetchOrders(u.id)).catch(e => console.error(e))

// async/await 写法
async function run() {
  try {
    const u = await fetchUser()
    const orders = await fetchOrders(u.id)
  } catch (e) {
    console.error(e)
  }
}

注意点:catch 只能捕获 await 表达式抛出的错误,如果你写成 const p = fetchUser()(不加 await),错误不会被这个 try 抓到,会变成未处理的 rejection。另外,async 函数里没被捕获的错误会让返回的 Promise rejected;如果连调用方也没 .catch(),Node.js 会触发 unhandledRejection,浏览器会报 unhandled promise rejection。

为什么用 await 写循环会变慢?

结论:for 循环里逐个 await 是串行执行,总耗时是各次请求之和,而不是最大值。

// 慢:串行,假设每个请求 300ms,10 个就是 3000ms
for (const id of ids) { await fetchItem(id) }

// 快:并行,约 300ms 左右
const results = await Promise.all(ids.map(id => fetchItem(id)))

这是最常见的 async/await 性能事故:.then() 链天然串行,但很多人改写成 await 后忘了并行。需要并行又有顺序需求时,用 Promise.all(一个失败全失败)、Promise.allSettled(等全部落定,不因失败中断)、Promise.race(谁先落定用谁)来控制。反过来,需要限流时(比如并发不超过 5 个),await 串行反而更省心。

什么时候该用 async/await,什么时候用 Promise?

结论:日常业务代码优先 async/await,需要组合、竞速、限流时用 Promise 的原生方法。

async/await 的优势是栈追踪清晰、断点调试友好、try/catch 作用域明确;Promise 组合子(all / allSettled / race / any)能表达的并发语义,async/await 写不出来,只能配合使用。

兼容性上:async/await 需要 Node.js 7.6+、Chrome 55+、Firefox 52+、Safari 10.1+;ES2022 的顶层 await 需要 Node.js 14.8+,且只在 ES Module(.mjs 或 "type": "module")中可用。如果必须支持 IE11,就得靠 Babel 转译成 generator + Promise(regenerator),产物体积会明显变大——这也是很多老项目坚持 .then() 的原因。

总结一下:async/await 内部就是 Promise,async 函数返回 Promise,await 是订阅 Promise 的语法;写代码时用 async/await 换可读性,用 Promise.all / allSettled 换并发性能,错误处理别忘了 try/catch 或 .catch() 兜底,循环里别无意中串行。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2229.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~