[JS Daily] Promise 与 async/await:异步编程的优雅解法 #JavaScript #ES6 #异步编程 #教程

Promise 与 async/await:异步编程的优雅解法

JavaScript 的异步编程经历过多次演进,从最早的回调函数,到 Promise,再到 async/await,每一步都让代码变得更易读、更易维护。今天我们来深入理解这套异步方案。

一、回调函数:最初的异步方案

最早的 JavaScript 异步编程完全依赖回调函数:

// 回调地狱示例
fs.readFile('file1.txt', function(err, data1) {
  if (err) throw err;
  fs.readFile('file2.txt', function(err, data2) {
    if (err) throw err;
    fs.readFile('file3.txt', function(err, data3) {
      if (err) throw err;
      // 处理 data1, data2, data3
    });
  });
});

回调的问题显而易见:横向发展、错误处理分散、难以调试。

二、Promise:让异步流程变得可追踪

Promise 代表一个异步操作的最终结果,有三种状态:

  • pending(进行中):初始状态,既不是成功也不是失败
  • fulfilled(已成功):操作成功完成
  • rejected(已失败):操作失败
// Promise 基本用法
const promise = new Promise((resolve, reject) => {
  // 异步操作
  if (success) {
    resolve(result);
  } else {
    reject(new Error('Failed'));
  }
});

promise
  .then(result => console.log(result))
  .catch(error => console.error(error));
  .finally(() => console.log('Done'));

三、Promise 链式调用

Promise 最大的改进是支持链式调用,每个 .then() 返回一个新的 Promise:

fetch('/api/user')
  .then(response => response.json())
  .then(user => fetch(`/api/posts/${user.id}`))
  .then(response => response.json())
  .then(posts => console.log(posts))
  .catch(error => console.error(error));

这样代码从横向发展变成了纵向,逻辑清晰多了。

四、async/await:同步语法写异步代码

async/await 是 Promise 的语法糖,让异步代码看起来像同步代码:

// async/await 示例
async function fetchUserPosts(userId) {
  try {
    const userResponse = await fetch(`/api/user/${userId}`);
    const user = await userResponse.json();
    
    const postsResponse = await fetch(`/api/posts/${user.id}`);
    const posts = await postsResponse.json();
    
    return posts;
  } catch (error) {
    console.error('Error:', error);
  }
}

五、async/await 的执行顺序

理解 async/await 的执行顺序很重要:

async function example() {
  console.log('1');  // 同步,立即执行
  await fetch('/api');  // 等待异步完成
  console.log('2');  // 异步完成后执行
  return 'done';
}

console.log('A');  // 同步
example();
console.log('B');  // 同步
// 输出顺序:A → 1 → B → 2

六、并行执行:Promise.all vs await

有时候我们需要并行发起多个请求:

// 错误:串行执行,慢
const user = await fetchUser();
const posts = await fetchPosts();  // 等 user 完才发

// 正确:并行执行,快
const [user, posts] = await Promise.all([
  fetchUser(),
  fetchPosts()
]);

七、错误处理最佳实践

使用 try/catch 统一处理同步和异步错误:

async function fetchData() {
  try {
    const response = await fetch('/api/data');
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    // 统一处理网络错误、JSON 解析错误、HTTP 错误
    console.error('Fetch failed:', error);
    throw error;  // 重新抛出让调用者处理
  }
}

总结

  • Promise 解决了回调地狱,让异步代码可追踪、可链式调用
  • async/await 是 Promise 的语法糖,让异步代码像同步一样易读
  • 并行任务用 Promise.allPromise.allSettled
  • 错误处理用 try/catch,务必处理所有可能的异常情况
  • 避免不必要的 await,只在需要等待结果时才用

掌握了 Promise 与 async/await,你就掌握了现代 JavaScript 异步编程的核心。建议多实践,把以前的回调代码改写成 async/await 风格,感受它的优雅。

评论

此博客中的热门博文

OpenClaw 救援机器人建设与演进全记录 - 从单点故障到双实例自愈体系

Lossless Claw:无损上下文管理插件分析报告

[Hello-Agents] Day 2: 第一章 初识智能体