返回分类
JavaScript中级
JavaScript Promise 与 async/await 详解
深入理解 Promise 异步编程模型及 async/await 语法糖
2026-03-26
阅读时间: 11分钟
JavaScript Promise 与 async/await 详解
Promise 是现代 JavaScript 异步编程的基础,理解 Promise 对于掌握 JavaScript 异步处理至关重要。
Promise 的基本概念
什么是 Promise
Promise 是 ES6 引入的用于处理异步操作的对象,它代表一个异步操作的最终完成或失败及其结果值。
Promise 有三种状态:
- Pending(待定):初始状态,既不是成功也不是失败
- Fulfilled(已兑现):操作成功完成
- Rejected(已拒绝):操作失败
一旦 Promise 状态改变(从 Pending 变为 Fulfilled 或 Rejected),就不可再变。
Promise 的基本用法
javascriptconst promise = new Promise((resolve, reject) => { // 异步操作 setTimeout(() => { const success = true; if (success) { resolve('操作成功!'); } else { reject(new Error('操作失败!')); } }, 1000); }); promise .then(result => console.log(result)) .catch(error => console.error(error)) .finally(() => console.log('操作完成'));
Promise 链式调用
Promise 的最大优势之一是支持链式调用,解决回调地狱问题。
then() 的返回值
javascriptfetch('/api/user') .then(response => response.json()) // 返回新的 Promise .then(user => fetch(`/api/posts/${user.id}`)) .then(response => response.json()) .then(posts => console.log(posts)) .catch(error => console.error(error));
返回值的处理
javascript// 返回值会被包装成 Promise Promise.resolve(1) .then(x => x + 1) // x = 1, 返回 2 .then(x => { return new Promise(resolve => setTimeout(() => resolve(x + 1), 1000)); }) .then(x => console.log(x)); // 1秒后输出 3
async/await
async/await 是 Promise 的语法糖,使异步代码看起来像同步代码。
基本语法
javascriptasync function fetchUser() { try { const response = await fetch('/api/user'); const user = await response.json(); return user; } catch (error) { console.error('获取用户失败:', error); } }
async 函数的返回值
async 函数总是返回 Promise:
javascriptasync function getNumber() { return 42; } getNumber().then(console.log); // 42
await 的使用规则
javascript// await 只能在 async 函数内部使用 async function example() { // 正确:直接在 async 函数中使用 const result = await someAsyncFunction(); // 错误:不能在普通函数中使用 // const result = await someAsyncFunction(); // SyntaxError }
Promise 组合
Promise.all
并行执行多个 Promise,全部成功才成功:
javascriptconst promise1 = fetch('/api/user/1'); const promise2 = fetch('/api/user/2'); const promise3 = fetch('/api/user/3'); const users = await Promise.all([promise1, promise2, promise3]); // 三个请求并行发出,全部完成后结果才可用
Promise.allSettled
等待所有 Promise 完成,无论成功或失败:
javascriptconst results = await Promise.allSettled([ fetch('/api/1'), fetch('/api/2'), fetch('/api/3') ]); results.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(`请求${index}成功:`, result.value); } else { console.log(`请求${index}失败:`, result.reason); } });
Promise.race
返回最先完成(无论成功或失败)的 Promise:
javascriptconst timeout = new Promise((_, reject) => setTimeout(() => reject(new Error('请求超时')), 5000) ); const request = fetch('/api/slow-endpoint'); Promise.race([request, timeout]) .then(result => console.log(result)) .catch(error => console.error(error)); // 5秒后超时
Promise.any
返回最先成功的 Promise(忽略失败):
javascriptconst request1 = fetch('/api/fast'); const request2 = fetch('/api/medium'); const request3 = fetch('/api/slow'); try { const result = await Promise.any([request1, request2, request3]); console.log('最先成功的请求:', result); } catch (error) { console.error('所有请求都失败了:', error.errors); }
常见面试问题
Q1: Promise.then() 和 async/await 的区别?
| 特性 | Promise.then() | async/await |
|---|---|---|
| 语法 | 链式调用 | 像同步代码 |
| 错误处理 | .catch() | try...catch |
| 调试 | 困难(异步堆栈) | 更易调试 |
| 适用场景 | 简单转换 | 复杂逻辑 |
Q2: async/await 和 Promise 的性能比较?
async/await 是 Promise 的语法糖,不存在性能差异。两者底层都是 Promise 机制。
Q3: 如何实现一个 Promise 重试机制?
javascriptasync function retry(fn, maxAttempts = 3, delay = 1000) { for (let attempt = 1; attempt <= maxAttempts; attempt++) { try { return await fn(); } catch (error) { if (attempt === maxAttempts) throw error; await new Promise(resolve => setTimeout(resolve, delay)); } } } // 使用 const data = await retry(() => fetch('/api/data').then(r => r.json()));
Q4: Promise.resolve() 和 new Promise() 的区别?
javascript// new Promise() 创建一个新的 Promise 实例 const p1 = new Promise((resolve) => resolve(1)); // Promise.resolve() 对已存在的 Promise 进行优化(不创建新实例) const p2 = Promise.resolve(1); console.log(p1 === p2); // false - 严格相等时不同 // 但值是相同的
Q5: 如何让 Promise 支持取消?
Promise 本身不支持取消,但可以使用 AbortController:
javascriptconst controller = new AbortController(); fetch('/api/data', { signal: controller.signal }) .then(response => response.json()) .then(console.log) .catch(err => { if (err.name === 'AbortError') { console.log('请求已取消'); } }); // 取消请求 controller.abort();
最佳实践
- 总是使用 async/await 或 Promise,避免回调地狱
- 正确处理错误,使用 try...catch 或 .catch()
- 避免不必要的 await,在可以并行时使用 Promise.all
- 使用 Promise.allSettled 而非 Promise.all 当需要所有结果时
- 避免在循环中使用 await,改用 Promise.all
javascript// ❌ 错误:串行执行,效率低 for (const url of urls) { const data = await fetch(url); } // ✅ 正确:并行执行 const results = await Promise.all(urls.map(url => fetch(url)));