标准答案
- 关系:async/await 是基于 Promise 的语法糖。async 函数一定返回 Promise;return 普通值会变成 fulfilled Promise,函数内部抛错会变成 rejected Promise。
- await 行为:await 后面可以跟 Promise 或普通值。遇到 Promise 时,async 函数会暂停后续执行,等 Promise settled 后再继续;await 后面的续执行会进入微任务。
- 异常处理:可以用 try/catch 包住 await,也可以让 async 函数返回 rejected Promise 交给外层 catch。无论哪种方式,都要保证调用方能处理失败。
- 并发写法:多个互不依赖的异步任务不要连续 await,否则会串行执行。应该先创建多个 Promise,再用 Promise.all、allSettled 等组合等待;只有后一个任务依赖前一个结果时才顺序 await。
题目解析
async/await 的价值是改善异步代码可读性,但它没有改变 Promise 的本质。async 函数返回 Promise,await 后续执行进入微任务,这些底层规则决定了错误处理和执行顺序。
最重要的工程点是并发和串行的区别。多个互不依赖的请求如果逐个 await,代码看起来顺,但性能会变差。判断标准是:后一个任务是否依赖前一个结果。
异常处理也不能只背 try/catch。async 函数内部抛错会变成 rejected Promise,如果调用方不 await、不 catch,仍然会形成未处理的 rejection。实际项目里要明确错误在哪一层收口。
如果多个请求都要展示部分结果,Promise.all 可能不是最佳选择,因为一个失败会导致整体失败。这个问题通常会自然引出 allSettled、请求取消和竞态处理。
代码示例
下面同时给出串行写法和并发写法,方便对比执行方式。
JavaScript
async function loadPageData() {
// 如果两个请求互不依赖,不要这样写:
// const user = await fetchUser()
// const posts = await fetchPosts()
const userTask = fetchUser()
const postsTask = fetchPosts()
try {
const [user, posts] = await Promise.all([userTask, postsTask])
return { user, posts }
} catch (error) {
// 统一处理请求失败
throw error
}
}常见误区
- 误以为 async 函数返回的是普通值。
- 在循环里无脑 await,导致本可以并发的请求变成串行。
- 只写 try/catch,不考虑 Promise.all 中一个失败会整体失败。