JavaScript如何实现异步编程_async和await如何工作?

async函数的本质是自动将返回值包装为Promise:正常返回值等价于Promise.resolve(),抛出异常等价于Promise.reject(),且必须返回Promise对象。

JavaScript 中的 asyncawait 是基于 Promise 的语法糖,让异步代码写起来像同步代码一样直观,但底层仍依赖事件循环和 Promise 状态机制。

async 函数的本质是什么?

async 关键字作用于函数声明或表达式,它会自动把函数返回值包装成一个 Promise:

  • 如果函数正常返回一个值(比如 return 42),实际返回的是 Promise.resolve(42)
  • 如果函数抛出异常(throw new Error()),等价于返回 Promise.reject(...)
  • 即使函数内部没有显式返回 Promise,调用它也会得到一个 Promise 对象。

await 只能在 async 函数里用,它做了什么?

await 并不是阻塞线程,而是“暂停当前 async 函数的执行”,把控制权交还给 JavaScript 引擎,等右侧的 Promise settle(fulfilled 或 rejected)后再继续:

  • 右侧必须是 thenable(有 .then() 方法的对象),通常是 Promise;
  • 如果 Promise 成功,await p 的结果就是 p 的 resolved 值;
  • 如果 Promise 失败,且没被 try/catch 捕获,就会让整个 async 函数返回 rejected Promise;
  • await 后面也可以跟非 Promise 值(如数字、字符串),这时会立即 resolve,等价于 await Promise.resolve(value)

async/await 和 Promise.then 链的关系

await 在逻辑上等价于 .then() 的展开,只是更易读。例如:

这段代码:
async function fetchUser() {
  const res = await fetch('/api/user');
  const user = await res.json();
  return user.name;
}

等价于:

function fetchUser() {
  return fetch('/api/user')
    .then(res => res.json())
    .then(user => user.name);
}

区别在于:前者错误处理统一用 try/catch,后者需在每个 .then() 后加 .catch() 或最后统一捕获。

常见陷阱和注意事项

  • 不能在顶层作用域直接用 await(ES2025 起支持顶层 await,但仅限模块内);
  • await 是串行的——想并发执行多个异步操作,要用 Promise.all([await a(), await b()]) 改成 await Promise.all([a(), b()])
  • 忘记处理 reject 会导致未捕获异常,建议始终用 try/catch 包裹关键 await 表达式;
  • await 不改变事件循环阶段,它只是让引擎在 microtask 队列中安排后续执行。