现在位置: 首页 > Node.js 教程 > 正文

Node.js async/await

在 Node.js 中,async/await 是一种处理异步操作的语法糖。

async/await 基于 Promise,但让异步代码看起来更像同步代码,极大地提高了代码的可读性和可维护性。

async 关键字用于声明一个函数是异步的,而 await 关键字用于等待一个 Promise 的解决(resolve)或拒绝(reject)。

使用 async/await 可以避免回调地狱(callback hell)并使错误处理更加直观。

JavaScript 是单线程的,遇到异步任务(如 setTimeout 或网络请求)时,会交给 浏览器 API 处理,完成后将回调放入消息队列。

事件循环不断检查调用栈是否为空,如果是,就从队列中取出回调推入调用栈执行。这样既不会阻塞主线程,又能按顺序处理异步结果。


基本语法

async 函数

任何函数都可以通过添加 async 关键字变成异步函数:

async function myFunction() {
  return "Hello World";
}

async 函数总是返回一个 Promise。如果返回值不是 Promise,它会被自动包装成 Promise。

await 表达式

await 只能在 async 函数内部使用,它会暂停函数的执行,等待 Promise 解决,然后继续执行并返回结果:

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}

错误处理

try/catch 方式

处理 async/await 错误最常用的方法是使用 try/catch

实例

async function getUser() {
  try {
    const response = await fetch('https://api.example.com/user');
    const user = await response.json();
    return user;
  } catch (error) {
    console.error('Error fetching user:', error);
    throw error; // 可以选择重新抛出错误
  }
}

直接处理 Promise

你也可以直接处理返回的 Promise:

实例

getUser()
  .then(user => console.log(user))
  .catch(error => console.error(error));

实际应用示例

并行执行多个异步操作

使用 Promise.all 结合 async/await 可以并行执行多个异步操作:

实例

async function fetchMultipleUrls(urls) {
  try {
    const requests = urls.map(url => fetch(url));
    const responses = await Promise.all(requests);
    const data = await Promise.all(responses.map(r => r.json()));
    return data;
  } catch (error) {
    console.error('Error fetching data:', error);
    throw error;
  }
}

数据库操作示例

实例

async function getUserAndPosts(userId) {
  try {
    const user = await User.findById(userId);
    const posts = await Post.find({ userId });
    return { user, posts };
  } catch (error) {
    console.error('Database error:', error);
    throw error;
  }
}

最佳实践

  1. 总是处理错误:不要忽略 await 可能抛出的错误,使用 try/catch.catch() 处理
  2. 避免不必要的 await:如果不需要等待结果,可以直接返回 Promise
  3. 合理使用并行:多个独立的异步操作应该并行执行(使用 Promise.all
  4. 保持代码清晰:避免过深的 async/await 嵌套,必要时提取函数
  5. 注意性能影响:每个 await 都会暂停函数执行,在循环中要特别注意

常见问题

async/await 与 Promise 的关系

async/await 是建立在 Promise 之上的语法糖。任何 async 函数都返回 Promise,任何 await 后面都可以接 Promise。

为什么我的 async 函数返回 undefined?

这可能是因为忘记在 await 前使用 return,或者在 Promise 解决前函数就退出了。

可以在顶层使用 await 吗?

在 ES 模块中(文件以 .mjs 结尾或 package.json"type": "module"),可以直接在顶层使用 await。在 CommonJS 模块中,需要包裹在 async 函数中。

实例

// 在 ES 模块中
const data = await fetchData();
console.log(data);