JavaScript async/await
async/await 是 ES2017 引入的异步编程语法糖,它建立在 Promise 之上,让你用"写同步代码"的方式写异步代码:不用再层层嵌套回调(回调地狱),也不用把逻辑拆进一长串 .then()。如今请求接口、读写数据库、处理定时器,几乎都用它,是现代 JavaScript 开发者的必修课。
async 函数
在普通函数前加 async 关键字,函数就变成异步函数,并且总是返回一个 Promise。即使你 return 一个普通值,它也会被自动包装成已兑现的 Promise:
async function hello() {
return "你好"; // 普通返回值
}
hello().then(msg => console.log(msg)); // 输出:你好
// 等价写法:显式返回 Promise
async function hello2() {
return Promise.resolve("你好");
}
await 关键字
await 只能出现在 async 函数内部(模块顶层的 await 另说)。它会暂停当前 async 函数,等右侧的 Promise 有了结果再继续执行,让代码可以一行行顺着读:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function main() {
console.log("开始"); // 输出:开始
await delay(1000); // 暂停 1 秒再继续
console.log("1 秒后继续"); // 输出:1 秒后继续
}
main();
如果 await 右侧不是 Promise,会把它当作已兑现的值直接使用。
错误处理:try/catch
当 await 的 Promise 被拒绝时,会在 await 那一行抛出异常,用 try/catch 就能捕获,比 .catch() 链更直观:
async function load() {
throw new Error("网络请求失败");
}
async function run() {
try {
await load();
} catch (err) {
console.log("捕获:" + err.message); // 输出:捕获:网络请求失败
}
}
run();
串行与并行
多个 await 逐个写就是串行(前一个完成后才开始下一个);互不依赖的任务应并行发起以节省时间:
async function step() {
// 串行:两秒左右依次完成
const a = await delay(1000);
const b = await delay(1000);
// 并行:Promise.all 同时发起,约 1 秒全部完成
const [x, y] = await Promise.all([delay(1000), delay(1000)]);
}
(以上片段需放进 async 函数中,并配合前面定义的 delay 一起运行。)
真实场景:配合 fetch 抓数据
async/await 最常见的用途是发送 HTTP 请求:
async function getUser(id) {
const res = await fetch("https://example.com/user/" + id);
if (!res.ok) throw new Error("HTTP " + res.status);
const data = await res.json(); // 解析 JSON 也是异步,需再等一次
console.log(data.name);
}
小结
async/await 让 Promise 代码像同步代码一样可读:async 声明异步函数并总是返回 Promise,await 暂停等待结果,try/catch 统一处理异常,并行任务交给 Promise.all。它是现代 JavaScript 异步编程的默认首选写法。