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 异步编程的默认首选写法。

笔记加载中…