async 是在函数门口挂个牌子"本房间办异步业务",await 是"在这一步停下来,等结果"。两个配合,让异步代码写得像同步代码——不再 .then 套 .then。
以前 .then 像"留个电话,好了打给我";await 像"站在原地等,好了再走下一步"。
function getData() { // 一个返回 Promise 的函数
return new Promise(resolve => { // 造一个承诺
setTimeout(() => resolve("数据来了"), 500); // 500 毫秒后兑现
});
}
// 以前:.then 回调接
getData.then(data => { // 好了再打给我
console.log(data); // 拿到结果
});
// 现在:async 函数里 await 等
async function main() { // 门口挂牌"办异步业务"
let data = await getData(); // ★ 在这里停住,等它出结果
console.log(data); // 等到了再打印
}
main(); // 调一下
await 会"拦住"代码:上一行等完,才执行下一行。结果直接当普通变量用,不用再写回调函数。
以前失败走 .catch,现在用同步代码那套 try...catch 接住就行。
// 以前
getData.then(d => console.log(d)) // 成功走 then
.catch(err => console.log("失败:", err)); // 失败走 catch
// 现在
async function main() { // async 函数里
try { // 包一层 try
let data = await getData(); // 失败会像普通异常一样抛出
console.log(data); // 成功就打印
} catch (err) { // 失败被 catch 接住
console.log("失败:", err); // catch 接住
}
}
await 的 Promise 失败时,会像普通代码一样"抛出异常",用 try...catch 就能接住,跟同步代码的错误处理完全一致。
async function main() { // async 函数里
let a = await getData("第一个"); // 等第一个
let b = await getData("第二个"); // 第一个完了才等第二个
console.log(a); // 打印第一个结果
console.log(b); // 打印第二个结果
}
注意:两个 await 是串行等待(总耗时相加)。如果两个请求互不依赖,应该用 Promise.all([p1, p2]) 并行,总耗时只取最长的——这是性能优化点。
// await 离开 async 函数会报错
// await getData; // ★ 报错(顶层要 ES2022 模块才支持)
// async 函数 return 的值,外面要 then / await 才能拿
async function fn() { // async 函数
return 123; // 你以为返回 123,其实返回 Promise<123>
}
fn.then(v => console.log(v)); // 123
如果你写了 const x = asyncFn 然后直接把 x 当数字用,会发现 x 是个 Promise 对象。因为 async 函数的返回值会自动被包成 Promise——外面必须再 await 或 .then 才能拿到真实值。
① 可能在什么地方用:接口请求后再渲染页面、登录后拉用户信息再跳转、按顺序执行的多步异步任务、封装"等结果再继续"的业务逻辑。
② 常见的问题:await 写在普通函数外面报错;async 函数 return 出来的直接当值用(其实是 Promise);多个不相关的 await 串行导致页面慢。
③ 解决思路:await 必须写在 async 函数或模块顶层;async 返回值再 await 一层;无依赖并发用 Promise.all([p1, p2]);失败一律 try...catch 包起来。