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

JavaScript 每日一题

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

#JavaScript #ES6 #异步编程 #教程

📋 本节要点

  • 理解 JavaScript 异步编程的本质与事件循环
  • 掌握 Promise 的三种状态与链式调用
  • 学会 async/await 语法糖的正确使用
  • 处理异步错误与并行任务的优化策略

一、为什么需要异步?

JavaScript 是单线程语言,这意味着同一时间只能执行一个任务。如果所有操作都是同步的,那么网络请求、文件读取、定时器等耗时操作会阻塞整个程序,导致页面卡死。

异步编程的核心思想是:把耗时任务交给其他模块处理,主线程继续执行后续代码。当任务完成时,通过回调、Promise 或 async/await 来处理结果。

💡 事件循环(Event Loop)

JavaScript 引擎通过事件循环机制管理异步任务。调用栈执行同步代码,任务队列排队异步回调。当调用栈空闲时,事件循环从任务队列取出回调执行。

二、Promise:异步的承诺

Promise 是 ES6 引入的异步解决方案,它代表一个未来才会知道结果的操作。Promise 有三种状态:

Pending
进行中
Fulfilled
已成功
Rejected
已失败

2.1 创建 Promise

const fetchData = new Promise((resolve, reject) => {     const success = true;          setTimeout(() => {         if (success) {             resolve({ data: 'Hello Promise' });         } else {             reject(new Error('请求失败'));         }     }, 1000); });

2.2 链式调用

Promise 的强大之处在于链式调用,避免回调地狱:

fetchData     .then(result => {         console.log(result.data); // 'Hello Promise'         return result.data.toUpperCase();     })     .then(upper => {         console.log(upper); // 'HELLO PROMISE'     })     .catch(error => {         console.error(error.message);     })     .finally(() => {         console.log('请求结束');     });

三、async/await:同步的写法

ES2017 引入的 async/await 是 Promise 的语法糖,让异步代码写起来像同步代码一样清晰。

3.1 基本语法

async function getData() {     try {         const result = await fetchData;         console.log(result.data);     } catch (error) {         console.error(error.message);     } }  getData();
📌 核心规则
  • async 函数返回值自动包装成 Promise
  • await 只能在 async 函数内使用
  • await 后面跟 Promise,如果不是会自动转成 resolved Promise

3.2 并行处理

当多个异步操作相互独立时,使用 Promise.all() 并行执行:

async function fetchAll() {     const [users, posts, comments] = await Promise.all([         fetch('/api/users'),         fetch('/api/posts'),         fetch('/api/comments')     ]);          return { users, posts, comments }; }

四、错误处理的最佳实践

async function safeRequest(url) {     try {         const response = await fetch(url);                  if (!response.ok) {             throw new Error(`HTTP ${response.status}`);         }                  return await response.json();     } catch (error) {         // 记录日志         console.error(`请求失败: ${url}`, error);                  // 返回默认值或重新抛出         throw error; // 或 return null;     } }

五、Promise vs async/await 对比

特性 Promise async/await
可读性 链式调用,中等 同步写法,最佳
错误处理 .catch() 统一处理 try/catch 同步风格
调试体验 断点不明显 断点直观清晰
并行处理 Promise.all() 原生支持 需要配合 Promise.all()
兼容性 ES6,广泛支持 ES2017,需转译

六、实战案例:API 请求封装

// 封装带重试的请求函数 async function requestWithRetry(url, options = {}, retries = 3) {     for (let i = 0; i < retries; i++) {         try {             const response = await fetch(url, options);             if (!response.ok) throw new Error(`HTTP ${response.status}`);             return await response.json();         } catch (error) {             if (i === retries - 1) throw error;             console.log(`重试 ${i + 1}/${retries}`);             await new Promise(r => setTimeout(r, 1000 * (i + 1)));         }     } }  // 使用示例 async function loadUserData() {     try {         const data = await requestWithRetry('/api/user');         console.log('用户数据:', data);     } catch (error) {         console.error('最终失败:', error);     } }

🎯 本节小结

  • Promise 是异步编程的基础,理解三种状态至关重要
  • async/await 让异步代码更易读、更易调试
  • 并行任务用 Promise.all(),错误处理用 try/catch
  • 实际项目中推荐封装统一的请求函数

📝 课后练习

  1. 手写一个 Promise.race() 的实现
  2. 将回调风格的 setTimeout 封装成 Promise
  3. 实现一个并发控制的请求函数(最多同时 N 个请求)

🦐 虾米团队 · JavaScript 每日一题系列

2026-03-18 · 第三期 · Promise 与 async/await

评论

此博客中的热门博文

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

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

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