JavaScript的 Promise,then,catch,finally,async,await 笔记250810
JavaScript 异步编程全面指南:Promise 与 async/await
一、Promise 核心概念
Promise 是 JavaScript 处理异步操作的基础,它表示一个异步操作的最终完成(或失败)及其结果值。
基本结构
const promise = new Promise((resolve, reject) => {
// 异步操作(如 API 请求、定时器等)
if (/* 成功 */) {
resolve(value); // 状态变为 Fulfilled
} else {
reject(error); // 状态变为 Rejected
}
});
三种状态
- Pending(进行中):初始状态
- Fulfilled(已成功):操作成功完成
- Rejected(已失败):操作失败
stateDiagram-v2
[*] --> Pending
Pending --> Fulfilled : resolve()
Pending --> Rejected : reject()
Fulfilled --> [*]
Rejected --> [*]
二、Promise 链式方法
1. .then() - 处理成功状态
promise.then(
result => console.log(result), // 成功处理
error => console.error(error) // 可选错误处理
);
2. .catch() - 处理错误
promise
.then(result => process(result))
.catch(error => console.error('捕获错误:', error));
3. .finally() - 最终处理
promise
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => console.log('操作完成'));
三、async/await 语法糖
async/await 是基于 Promise 的语法糖,使异步代码更易读、更同步化。
1. async 函数
async function fetchData() {
return '数据'; // 自动包装为 Promise.resolve('数据')
}
2. await 表达式
async function getUser() {
try {
const response = await fetch('/api/user');
const user = await response.json();
return user;
} catch (error) {
console.error('获取用户失败:', error);
throw error;
}
}
四、Promise 与 async/await 互转
Promise → async/await
// Promise 链
function getData() {
return fetchData()
.then(processData)
.catch(handleError);
}
// async/await 等价形式
async function getData() {
try {
const data = await fetchData();
return processData(data);
} catch (error) {
return handleError(error);
}
}
async/await → Promise
// async/await 形式
async function loadResources() {
const [res1, res2] = await Promise.all([fetchA(), fetchB()]);
return { res1, res2 };
}
// Promise 等价形式
function loadResources() {
return Promise.all([fetchA(), fetchB()])
.then(([res1, res2]) => ({ res1, res2 }));
}
五、错误处理对比
Promise 方式
fetchData()
.then(process)
.then(save)
.catch(error => console.error('链中任何错误:', error));
async/await 方式
async function processData() {
try {
const data = await fetchData();
const processed = await process(data);
await save(processed);
} catch (error) {
console.error('捕获错误:', error);
} finally {
console.log('清理资源');
}
}
六、并行执行模式
1. Promise.all()
Promise.all([fetchUser(), fetchOrders()])
.then(([user, orders]) => renderUI(user, orders))
.catch(error => console.error('任一请求失败:', error));
2. async/await 并行
async function loadDashboard() {
const [user, orders] = await Promise.all([
fetchUser(),
fetchOrders()
]);
return { user, orders };
}
3. Promise.race()
Promise.race([
fetchWithTimeout('/api', 5000),
timeout(3000) // 3秒超时
])
.then(data => console.log('第一个完成的结果:', data))
.catch(error => console.error('错误或超时:', error));
七、最佳实践与模式
1. 避免回调地狱
// 回调地狱
getUser(userId, (user) => {
getProfile(user.id, (profile) => {
saveProfile(profile, () => {
// 更多嵌套...
}, handleError);
}, handleError);
}, handleError);
// Promise 改进
getUser(userId)
.then(user => getProfile(user.id))
.then(profile => saveProfile(profile))
.catch(handleError);
2. 合理使用 async/await
// 错误:顺序执行独立操作
async function slowProcess() {
const a = await getA(); // 等待A完成
const b = await getB(); // 再开始B(不必要等待)
return a + b;
}
// 正确:并行执行
async function fastProcess() {
const [a, b] = await Promise.all([getA(), getB()]);
return a + b;
}
3. 错误处理策略
// 局部错误处理
async function updateUser(user) {
try {
await validateUser(user);
} catch (error) {
return { error: '验证失败' };
}
// 全局错误处理
try {
await saveUser(user);
return { success: true };
} catch (error) {
logError(error);
throw error;
}
}
八、常见误区与解决方案
1. 忘记 await
async function process() {
const data = fetchData(); // 错误:缺少await
// data是Promise对象,不是实际数据
}
2. 错误处理遗漏
// 危险:未处理错误
async function criticalTask() {
await criticalOperation();
}
// 安全:添加错误处理
async function safeTask() {
try {
await criticalOperation();
} catch (error) {
logError(error);
throw error;
}
}
3. 不必要的 async
// 不必要的 async
async function getConfig() {
return { setting: 'value' };
// 等同于 return Promise.resolve({ setting: 'value' })
}
// 更简洁
function getConfig() {
return { setting: 'value' };
}
九、高级模式
1. 异步生成器
async function* asyncGenerator() {
let i = 0;
while (i < 3) {
await sleep(1000);
yield i++;
}
}
(async () => {
for await (const num of asyncGenerator()) {
console.log(num); // 0, 1, 2 (每秒输出)
}
})();
2. 取消异步操作
function cancellableFetch(url) {
const controller = new AbortController();
const promise = fetch(url, {
signal: controller.signal
});
return {
promise,
cancel: () => controller.abort()
};
}
// 使用
const { promise, cancel } = cancellableFetch('/api/data');
setTimeout(cancel, 5000); // 5秒后取消
3. 重试机制
async function fetchWithRetry(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await fetch(url);
} catch (err) {
if (i === retries - 1) throw err;
await sleep(1000 * (i + 1)); // 指数退避
}
}
}
十、总结对比
| 特性 | Promise | async/await |
|---|---|---|
| 可读性 | 链式调用,嵌套复杂 | 类似同步代码,直观清晰 |
| 错误处理 | .catch() 方法 | try/catch 结构 |
| 调试 | 链式调用调试困难 | 可直接断点调试 |
| 流程控制 | .then() 链式控制 | 使用标准控制结构 |
| 并行处理 | Promise.all() | await Promise.all() |
| 返回值 | 总是返回 Promise | 总是返回 Promise |
何时选择哪种方式?
- 简单链式操作:Promise 更简洁
- 复杂业务逻辑:async/await 更易维护
- 并行多个请求:Promise.all + await
- 错误处理复杂:async/await + try/catch
- 事件处理程序:Promise 链更合适
终极建议
async function optimalApproach() {
// 并行执行
const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
// 顺序处理
const processed = await processData(data1);
// 后台操作(无需等待)
sendAnalytics(processed).catch(handleAnalyticsError);
return { data2, processed };
}
掌握 Promise 和 async/await 是现代 JavaScript 开发的必备技能。理解它们的核心概念、转换关系和适用场景,能让你编写出更健壮、可维护的异步代码。
1️⃣ 参考 1
JavaScript 的异步处理经历了从回调函数到 Promise,再到 async/await 的演进。以下是核心概念详解:
1. Promise(承诺) 表示异步操作的最终完成或失败及其结果值。
const promise = new Promise((resolve, reject) => {
// 异步操作(如 API 请求)
if (success) resolve(value) // 成功状态
else reject(error) // 失败状态
})
状态变化:
pending(进行中)→fulfilled(已成功)pending(进行中)→rejected(已失败)
⚠️ 状态一旦改变不可逆
2. .then() 处理 Promise 成功状态,返回新 Promise 实现链式调用。
promise
.then(value => {
console.log("成功:", value)
return newValue // 传递给下一个 then
})
3. .catch() 捕获链式调用中任意位置的错误(推荐替代 .then 的第二个参数)
promise
.then(step1)
.then(step2)
.catch(error => {
console.error("捕获所有错误:", error)
})
4. .finally() 无论成功/失败必然执行,适用于清理操作
promise
.then(handleSuccess)
.catch(handleError)
.finally(() => {
console.log("无论结果如何都会执行")
// 例如隐藏加载动画
})
5. async/await(语法糖) async 函数:
- 总是返回 Promise
- 内部可用
await
async function fetchData() {
return "data" // 等价于 Promise.resolve("data")
}
await:
- 暂停 async 函数执行,等待 Promise 解决
- 只能用在 async 函数中
async function getUser() {
try {
const response = await fetch('/api/user') // 等待 Promise 解决
const data = await response.json() // 再次等待
return data
} catch (error) {
console.error("请求失败:", error)
}
}
关键对比表
| 特性 | Promise.then() | async/await |
|---|---|---|
| 可读性 | 链式调用,可能嵌套 | 类同步代码,线性执行 |
| 错误处理 | .catch() 或 then 的第二个参数 | try/catch 块 |
| 调试 | 链式调用调试困难 | 可像同步代码断点调试 |
| 返回值 | 总是返回 Promise | async 函数总返回 Promise |
| 并行请求 | Promise.all() | await Promise.all([...]) |
最佳实践 1. 并行优化(避免顺序等待)
// ✅ 正确:并行请求
async function fetchAll() {
const [user, posts] = await Promise.all([
fetch('/user'),
fetch('/posts')
])
}
// ❌ 低效:顺序等待
async function slowFetch() {
const user = await fetch('/user') // 等待完成
const posts = await fetch('/posts') // 才开始
}
2. 错误处理统一
// 使用 catch 处理 async 函数错误
fetchData()
.then(data => process(data))
.catch(error => handleError(error)) // 捕获 async 函数中的错误
3. 避免 await 滥用
// ❌ 不必要的 await
async function update(data) {
return await api.update(data)
// 等效于:return api.update(data)
}
// ✅ 直接返回 Promise
async function update(data) {
return api.update(data)
}
执行顺序经典题
console.log(1)
setTimeout(() => console.log(2), 0)
Promise.resolve()
.then(() => console.log(3))
.then(() => console.log(4))
async function run() {
console.log(5)
await Promise.resolve()
console.log(6)
}
run()
console.log(7)
// 输出顺序:1 → 5 → 7 → 3 → 6 → 4 → 2
解析:
- 同步代码:
1, 5, 7 - 微任务(Promise/await):
3, 6, 4 - 宏任务(setTimeout):
2
📌 事件循环优先级:同步代码 > 微任务 > 宏任务
掌握这些核心概念,能让你在回调地狱、Promise 链和同步式异步代码之间灵活选择!
2️⃣ 参考 2
JavaScript 异步编程全面解析:Promise 与 async/await
一、Promise 核心概念
Promise 是 JavaScript 处理异步操作的核心对象,表示一个异步操作的最终完成(或失败)及其结果值。
Promise 的生命周期
- Pending:初始状态,操作未完成
- Fulfilled:操作成功完成
- Rejected:操作失败
创建 Promise
const myPromise = new Promise((resolve, reject) => {
// 异步操作(如 API 调用、定时器等)
if (/* 操作成功 */) {
resolve('成功结果'); // 状态变为 Fulfilled
} else {
reject(new Error('错误信息')); // 状态变为 Rejected
}
});
二、Promise 方法链
1. .then() - 处理成功状态
myPromise.then(
result => {
console.log('成功:', result);
return result + '处理';
}
);
2. .catch() - 处理失败状态
myPromise.catch(
error => {
console.error('失败:', error.message);
return '默认值';
}
);
3. .finally() - 最终清理
myPromise.finally(() => {
console.log('无论成功失败都会执行');
});
完整链式调用示例
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log('数据:', data);
return processData(data);
})
.catch(error => {
console.error('请求失败:', error);
return getCachedData();
})
.finally(() => {
console.log('请求处理完成');
});
三、async/await 语法糖
async/await 是基于 Promise 的语法糖,让异步代码看起来像同步代码。
1. async 函数
async function fetchData() {
// 函数始终返回 Promise
return '数据';
}
// 等价于
function fetchData() {
return Promise.resolve('数据');
}
2. await 表达式
async function getUser() {
try {
const response = await fetch('/api/user'); // 暂停执行直到 Promise 完成
const data = await response.json(); // 再次等待
return data;
} catch (error) {
console.error('获取用户失败:', error);
}
}
四、Promise 与 async/await 对比
相同异步操作的不同写法
// Promise 写法
function loadData() {
fetch('/api/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
}
// async/await 写法
async function loadData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
错误处理对比
// Promise 错误处理
fetchData()
.then(handleSuccess)
.catch(handleError); // 捕获所有错误
// async/await 错误处理
async function main() {
try {
const result = await fetchData();
handleSuccess(result);
} catch (error) {
handleError(error);
}
}
五、高级用法与最佳实践
1. 并行执行多个异步操作
// 使用 Promise.all
async function fetchAll() {
const [user, posts] = await Promise.all([
fetch('/api/user'),
fetch('/api/posts')
]);
// 继续处理结果...
}
// 使用 Promise.allSettled(需要所有结果)
const results = await Promise.allSettled([
fetchResource1(),
fetchResource2()
]);
2. 异步循环处理
// 顺序执行
async function processArray(array) {
for (const item of array) {
await processItem(item); // 逐个等待完成
}
}
// 并行执行
async function processArrayParallel(array) {
await Promise.all(array.map(item => processItem(item)));
}
3. 错误处理模式
// 方式1:try/catch
async function safeFetch() {
try {
return await fetch('/api/data');
} catch (error) {
return null;
}
}
// 方式2:Promise.catch
async function safeFetch() {
return fetch('/api/data').catch(() => null);
}
// 方式3:辅助函数
function to(promise) {
return promise
.then(data => [null, data])
.catch(error => [error, null]);
}
async function main() {
const [err, data] = await to(fetch('/api/data'));
if (err) {
// 处理错误
}
}
六、常见陷阱与解决方案
1. 忘记 await
async function example() {
const promise = fetchData(); // 缺少 await → 得到 Promise 对象
console.log(promise); // 输出: Promise {<pending>}
// 正确
const result = await fetchData();
}
2. 循环中的 await 误用
// 低效:顺序执行
for (const url of urls) {
await fetch(url); // 每次等待
}
// 高效:并行执行
const promises = urls.map(url => fetch(url));
await Promise.all(promises);
3. 未处理的 Promise 拒绝
async function dangerous() {
throw new Error('未捕获');
}
// 解决方案1:添加 catch
dangerous().catch(console.error);
// 解决方案2:在 async 函数中使用 try/catch
async function safeCall() {
try {
await dangerous();
} catch (err) {
// 处理错误
}
}
七、浏览器与 Node.js 支持
- Promise:所有现代浏览器(包括 IE11)和 Node.js 0.12+
- async/await:
- 浏览器:Chrome 55+, Firefox 52+, Safari 10.1+, Edge 15+
- Node.js:7.6+(建议使用 10.0+ 版本)
总结对比表
| 特性 | Promise | async/await |
|---|---|---|
| 语法 | 链式调用(.then/.catch) | 类似同步代码 |
| 错误处理 | .catch() 方法 | try/catch 块 |
| 可读性 | 中等(回调金字塔风险) | 高(线性执行) |
| 调试 | 较困难(匿名函数) | 容易(标准调用栈) |
| 返回值 | 必须返回 Promise | 自动包装为 Promise |
| 并行处理 | Promise.all() | Promise.all() + await |
| 循环处理 | 需要 Promise 链 | for 循环 + await |
最佳实践建议:
- 新项目优先使用 async/await
- 复杂异步逻辑使用 Promise 组合方法(all、race 等)
- 始终处理可能的错误(try/catch 或 .catch)
- 避免不必要的顺序等待,尽可能并行化
- 使用 lint 规则防止忘记 await(如 ESLint 的 require-await)
掌握 Promise 和 async/await 的组合使用,可以让你编写出既高效又易读的异步 JavaScript 代码,显著提升开发体验和应用性能。
3️⃣ 参考 3
在 JavaScript 中,Promise 和 async/await 是处理异步操作的核心机制。下面我将系统化地解释这些概念,并提供使用示例:
一、Promise 核心概念 Promise 是一个表示异步操作最终完成或失败的对象,包含三种状态:
- Pending(进行中):初始状态
- Fulfilled(已成功):操作成功完成
- Rejected(已失败):操作失败
创建 Promise:
const promise = new Promise((resolve, reject) => {
// 异步操作(如 API 请求、定时器等)
setTimeout(() => {
const success = Math.random() > 0.5;
success ? resolve("Success!") : reject("Error occurred");
}, 1000);
});
二、Promise 方法链 1. .then() - 处理成功状态
promise.then(result => {
console.log(result); // "Success!"
});
2. .catch() - 处理失败状态
promise.catch(error => {
console.error(error); // "Error occurred"
});
3. .finally() - 无论成功失败都会执行
promise.finally(() => {
console.log("Operation completed");
});
完整链式调用示例:
fetch("/api/data")
.then(response => response.json())
.then(data => processData(data))
.catch(error => handleError(error))
.finally(() => cleanUp());
三、async/await 语法糖 async/await 是基于 Promise 的语法糖,让异步代码更像同步代码:
1. async 函数
- 总是返回 Promise
- 允许在函数内使用
await
async function fetchData() {
return "Data"; // 等价于 Promise.resolve("Data")
}
2. await 表达式
- 暂停 async 函数执行,等待 Promise 解决
- 只能用在 async 函数内部
async function getUser() {
try {
const response = await fetch("/api/user"); // 等待 Promise 解决
const data = await response.json(); // 再次等待
return data;
} catch (error) {
console.error("Fetch failed:", error);
}
}
四、对比与转换
Promise → async/await 转换
// Promise 版本
function loadData() {
return fetchData()
.then(process)
.catch(handleError);
}
// async/await 版本
async function loadData() {
try {
const data = await fetchData();
return process(data);
} catch (error) {
handleError(error);
}
}
async/await → Promise 转换
// async/await 版本
async function calculate() {
const a = await getValueA();
const b = await getValueB();
return a + b;
}
// Promise 版本
function calculate() {
return getValueA()
.then(a => getValueB().then(b => a + b));
}
五、最佳实践与陷阱
1. 错误处理对比
// Promise
fetchData()
.then(handleSuccess)
.catch(handleError); // 捕获所有上游错误
// async/await
async function main() {
try {
const data = await fetchData();
handleSuccess(data);
} catch (err) {
handleError(err); // 需要包裹整个逻辑
}
}
2. 并行执行优化
// 低效(顺序执行)
const a = await fetchA();
const b = await fetchB(); // 等待 A 完成才开始
// 高效(并行执行)
const [a, b] = await Promise.all([fetchA(), fetchB()]);
3. 循环中的注意事项
// 错误:在 forEach 中使用 await
items.forEach(async item => {
await process(item); // 不会按预期等待
});
// 正确:使用 for...of
for (const item of items) {
await process(item); // 顺序执行
}
六、关键区别总结
| 特性 | Promise.then | async/await |
|---|---|---|
| 代码结构 | 链式调用 | 同步风格 |
| 错误处理 | .catch() 方法 | try/catch 语句 |
| 调试体验 | 回调跳转难跟踪 | 直线执行易调试 |
| 返回值 | 必须返回新 Promise | 自动包装为 Promise |
| 并行处理 | Promise.all 显式处理 | 需手动结合 Promise.all |
七、高级模式 1. Promise 组合
// 竞速模式(第一个完成/失败的)
Promise.race([fetchA(), fetchB()]);
// 全完成(即使有失败)
Promise.allSettled([fetchA(), fetchB()]);
2. async 函数中的 return vs return await
async function example() {
// 直接返回:错误不会在本地捕获
return fetchData();
// 推荐:允许本地错误处理
return await fetchData();
}
3. 顶层 await(ES2022+)
// 模块顶层直接使用
const data = await fetchData();
console.log(data);
总结建议:
- 对于简单链式调用 → Promise.then
- 对于复杂异步流程 → async/await
- 需要并行处理时 → 结合 Promise.all 和 await
- 始终处理错误 → .catch() 或 try/catch
理解这些概念的关系和转换规则,能让你根据场景灵活选择最合适的异步处理方式,编写更清晰、健壮的 JavaScript 代码。
4️⃣ 参考 4
JavaScript 异步编程全面解析:Promise、then、catch、finally、async、await
一、Promise 核心概念
1. Promise 的本质
- 异步操作的容器:表示一个尚未完成但预期会完成的操作
- 三种状态:
pending(进行中)fulfilled(已成功)rejected(已失败)
- 状态不可逆:从 pending 到 fulfilled 或 rejected 后不可更改
2. 创建 Promise
const promise = new Promise((resolve, reject) => {
// 异步操作(API请求、定时器等)
if (/* 成功条件 */) {
resolve(value); // 状态变为 fulfilled
} else {
reject(error); // 状态变为 rejected
}
});
3. Promise 生命周期
stateDiagram-v2
[*] --> Pending
Pending --> Fulfilled: resolve(value)
Pending --> Rejected: reject(error)
Fulfilled --> [*]
Rejected --> [*]
二、Promise 链式方法
1. .then() - 处理成功/失败
promise.then(
onFulfilled, // (value) => { ... }
onRejected // 可选 (error) => { ... }
);
特性:
- 返回新 Promise,支持链式调用
- 返回值自动包装为 Promise:
- 返回普通值 →
Promise.resolve(值) - 抛出错误 →
Promise.reject(错误) - 返回 Promise → 直接传递
- 返回普通值 →
2. .catch() - 错误处理
promise.catch(onRejected); // (error) => { ... }
特性:
- 捕获链中所有未处理的错误
- 可修复错误状态(通过返回值)
- 相当于
.then(null, onRejected)
3. .finally() - 最终清理
promise.finally(onFinally); // () => { ... }
特性:
- 无论成功失败都会执行
- 不接收参数(无法知道最终状态)
- 传递原始结果(不影响返回值)
- 适合资源清理工作
4. 完整链式示例
fetchData()
.then(data => process(data)) // 成功处理
.then(result => save(result)) // 链式传递
.catch(error => { // 错误捕获
console.error('失败:', error);
return fallback(); // 错误修复
})
.finally(() => { // 最终清理
cleanResources();
});
三、async/await 革命性语法
1. async 函数
async function fetchUser() {
return { id: 1, name: 'Alice' };
// 等价于 return Promise.resolve({ id: 1, name: 'Alice' })
}
特性:
- 总是返回 Promise 对象
- 普通返回值自动包装为 resolved Promise
- 抛出错误自动包装为 rejected Promise
2. await 表达式
async function loadData() {
try {
const response = await fetch('/api/data'); // 等待Promise完成
const data = await response.json(); // 等待JSON解析
return process(data);
} catch (error) {
handleError(error);
}
}
规则:
- 只能在 async 函数中使用
- 暂停函数执行(非阻塞主线程)
- 返回 Promise 的解决值
- 如 Promise 被拒绝,抛出拒绝原因
四、Promise 与 async/await 对比
| 特性 | Promise | async/await |
|---|---|---|
| 代码结构 | 链式调用 | 同步风格 |
| 可读性 | 回调嵌套可能复杂 | 线性结构更清晰 |
| 错误处理 | .catch() 方法 | try/catch 块 |
| 调试体验 | 断点在回调间跳转 | 像同步代码调试 |
| 返回值 | 显式返回Promise | 自动包装为Promise |
| 循环处理 | 需要特殊处理 | 可使用常规循环 |
五、最佳实践与模式
1. 错误处理方案
// 方案1: try/catch (推荐)
async function safeFetch() {
try {
const data = await fetchData();
return process(data);
} catch (error) {
handleError(error);
return fallbackValue;
}
}
// 方案2: .catch()
fetchData()
.then(process)
.catch(handleError);
2. 并行执行优化
// 顺序执行 (慢)
const user = await getUser();
const posts = await getPosts(user.id);
// 并行执行 (快)
const [user, posts] = await Promise.all([
getUser(),
getPosts() // 不依赖user
]);
3. 提前启动请求
async function loadDashboard() {
// 提前启动独立请求
const userPromise = getUser();
const statsPromise = getStats();
// 执行其他同步任务
renderSkeleton();
// 等待需要的数据
const [user, stats] = await Promise.all([userPromise, statsPromise]);
renderDashboard(user, stats);
}
4. 超时控制实现
function withTimeout(promise, timeout) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('操作超时')), timeout)
)
]);
}
async function fetchWithTimeout() {
try {
return await withTimeout(fetch('/api'), 5000);
} catch (error) {
if (error.message === '操作超时') {
return cachedData;
}
throw error;
}
}
六、常见问题与解决方案
1. Promise 常见误区
// 错误1: 忘记返回Promise
function fetchData() {
return fetch('/api').then(res => res.json()); // 正确
}
// 错误2: 未处理拒绝
fetchData(); // ❌ 未处理可能的错误
fetchData().catch(logError); // ✅
// 错误3: 回调地狱
fetchUser(userId)
.then(user => {
fetchPosts(user.id).then(posts => { // ❌ 嵌套
// ...
});
});
2. async/await 陷阱
// 陷阱1: 在循环中顺序等待
async function slowProcess(items) {
for (const item of items) {
await process(item); // ❌ 顺序执行效率低
}
}
// 改进方案
async function fastProcess(items) {
await Promise.all(items.map(item => process(item))); // ✅ 并行
}
// 陷阱2: 忘记await
async function updateData() {
const data = fetchData(); // ❌ 忘记await
save(data); // 错误: data是Promise对象
}
七、高级应用场景
1. 异步构造函数模式
class DataLoader {
constructor() {
this.initialized = this.init();
}
async init() {
this.config = await loadConfig();
this.cache = await createCache();
}
async getData() {
await this.initialized; // 确保初始化完成
return fetchData(this.config.endpoint);
}
}
2. 取消异步操作
function cancellable(promise) {
let cancel;
const wrapped = new Promise((resolve, reject) => {
cancel = reject;
promise.then(resolve).catch(reject);
});
return [wrapped, () => cancel(new Error('操作取消'))];
}
// 使用
const [fetchPromise, cancel] = cancellable(fetchData());
cancelButton.addEventListener('click', cancel);
3. 进度通知
function withProgress(promise, onProgress) {
return new Promise((resolve, reject) => {
promise
.then(result => {
onProgress(100);
resolve(result);
})
.catch(reject);
// 模拟进度更新
const interval = setInterval(() => {
const progress = /* 计算进度 */;
onProgress(progress);
if (progress >= 100) clearInterval(interval);
}, 100);
});
}
八、执行机制与事件循环
1. 微任务队列
console.log('开始');
Promise.resolve()
.then(() => console.log('微任务1'))
.then(() => console.log('微任务2'));
setTimeout(() => console.log('宏任务'), 0);
console.log('结束');
/* 输出顺序:
开始
结束
微任务1
微任务2
宏任务
*/
2. async/await 执行流程
sequenceDiagram
participant M as 主线程
participant A as async 函数
participant P as Promise
M->>A: 调用 async 函数
A->>A: 执行同步代码
A->>P: await 暂停执行
M->>M: 继续执行后续代码
P-->>A: Promise 解决
A->>A: 恢复执行
A->>M: 返回最终结果
九、总结与选择指南
核心概念对比
| 概念 | 角色 | 关键特性 |
|---|---|---|
Promise | 异步操作的容器 | 状态不可逆、支持链式调用 |
.then() | 处理异步结果 | 返回新Promise、链式流动 |
.catch() | 错误处理 | 捕获未处理错误、可修复状态 |
.finally() | 最终清理 | 无视状态执行、传递原始结果 |
async | 定义异步函数 | 自动返回Promise、启用await |
await | 暂停异步执行 | 等待Promise解决、同步风格编码 |
何时选择何种方案
graph TD
A[开始] --> B{简单单步操作?}
B -->|是| C[Promise.then/catch]
B -->|否| D{需要同步编码风格?}
D -->|是| E[async/await]
D -->|否| F{并行处理多个操作?}
F -->|是| G[Promise.all + async/await]
F -->|否| H[Promise链式调用]
黄金法则
- 理解基础:掌握 Promise 状态机机制
- 优先 async/await:提升代码可读性和可维护性
- 组合使用:async/await + Promise.all 兼顾清晰与效率
- 始终处理错误:使用 try/catch 或 .catch() 避免未处理拒绝
- 合理并行化:使用 Promise.all 优化独立异步操作
通过深入理解 Promise 和 async/await 的工作原理及适用场景,您可以编写出更健壮、更高效的 JavaScript 异步代码,轻松应对从简单到复杂的各种异步编程需求。
5️⃣ 参考 5
在 JavaScript 中,Promise、then/catch/finally 和 async/await 共同构成了处理异步操作的核心机制。以下是它们的全面解析:
一、Promise 核心概念 Promise 是一个表示异步操作最终完成或失败的对象,包含三种状态:
- pending:初始状态(未完成)
- fulfilled:操作成功完成
- rejected:操作失败
const promise = new Promise((resolve, reject) => {
// 异步操作(如 API 请求、定时器等)
if (success) resolve(value); // 状态变为 fulfilled
else reject(error); // 状态变为 rejected
});
二、Promise 链式方法 1. .then() - 处理成功状态 接收两个回调函数(可选):
promise.then(
value => { /* 处理成功结果 */ },
error => { /* 可选:处理错误(不推荐) */ }
);
2. .catch() - 捕获错误 专门处理 rejected 状态:
promise
.then(value => { ... })
.catch(error => { /* 捕获所有错误 */ });
3. .finally() - 最终清理 无论成功失败都会执行:
promise
.then(...)
.catch(...)
.finally(() => { /* 清理资源 */ });
三、async/await - 语法糖 1. async 函数
- 声明异步函数,总是返回 Promise
- 函数内可使用
await
async function fetchData() {
return "data"; // 等价于 Promise.resolve("data")
}
2. await 表达式
- 暂停 async 函数执行,等待 Promise 完成
- 只能在 async 函数中使用
async function getUser() {
const response = await fetch('/user'); // 等待请求完成
return response.json();
}
四、组合使用示例 完整工作流:
async function loadData() {
try {
// 1. 等待请求完成
const response = await fetch('/api/data');
// 2. 检查响应状态
if (!response.ok) throw new Error('请求失败');
// 3. 等待 JSON 解析
const data = await response.json();
// 4. 返回最终结果
return { data, status: 'success' };
} catch (error) {
// 5. 错误处理
console.error('加载失败:', error);
return { status: 'failed' };
} finally {
// 6. 清理操作
console.log('请求结束');
}
}
// 使用 Promise 方法处理结果
loadData()
.then(result => console.log(result))
.catch(finalError => console.error(finalError)); // 最终兜底
五、关键对比与关系
| 特性 | Promise + .then | async/await | 说明 |
|---|---|---|---|
| 代码结构 | 链式调用 | 类同步写法 | async/await 更易阅读 |
| 错误处理 | .catch() 或 then 的第二个参数 | try/catch 同步语法 | async/await 更直观 |
| 返回值 | 返回新 Promise | 自动包装为 Promise | 两者本质相同 |
| 执行控制 | 微任务队列调度 | 函数内暂停执行 | 底层机制一致 |
| 并行处理 | Promise.all()/Promise.race() | 需结合 Promise.all() 使用 | 并行逻辑无差异 |
| 调试体验 | 断点跳转可能混乱 | 支持同步式断点调试 | async/await 更易调试 |
六、最佳实践指南
-
错误处理优先级:
// 👍 推荐:集中错误处理 async function main() { try { await operation(); } catch (error) { // 统一处理 } } // 👎 避免:混合风格 async function risky() { await operation().catch(...); // 导致部分错误被吞没 } -
并行优化:
// 串行(慢): const a = await getA(); const b = await getB(); // 等待 getA 完成 // 并行(快): const [a, b] = await Promise.all([getA(), getB()]); -
循环中的注意事项:
// 错误:意外串行 for (const url of urls) { await fetch(url); // 逐个请求 } // 正确:并行请求 const promises = urls.map(url => fetch(url)); await Promise.all(promises); -
避免阻塞陷阱:
// 👎 阻塞主线程 async function blocking() { await heavyTask(); // 虽不阻塞主线程,但阻塞函数内后续代码 renderUI(); // 延迟执行 } // 👍 非阻塞优化 function nonBlocking() { heavyTask().then(() => renderUI()); // 立即返回 }
七、常见误区解析
-
忘记 await:
async function save() { const result = writeToDB(); // 忘记 await → 返回 Promise 而非结果 console.log(result); // 输出 Promise 对象 } -
冗余 async:
// 不必要的 async const getId = async () => 123; // 返回 Promise<number> // 更简洁写法 const getId = () => Promise.resolve(123); -
顶层 await 限制:
// 模块顶层合法(ES2022) const data = await fetchData(); // 需在模块环境中 // 非模块环境需包裹 (async () => { const data = await fetchData(); })();
八、升级路线图
- 回调地狱 →
Promise→async/await// 回调地狱 fs.readFile('a.txt', (err, dataA) => { fs.readFile('b.txt', (err, dataB) => { // 更多嵌套... }); }); // Promise 改进 readFilePromise('a.txt') .then(dataA => readFilePromise('b.txt')) .then(dataB => ...); // async/await 终极方案 const dataA = await readFile('a.txt'); const dataB = await readFile('b.txt');
总结表格
| 概念 | 角色 | 关键特性 |
|---|---|---|
| Promise | 异步操作容器 | 状态不可逆、链式传播 |
| .then() | 成功回调处理器 | 返回新 Promise |
| .catch() | 错误捕获器 | 捕获链中任意错误 |
| .finally() | 最终清理器 | 与状态无关,必执行 |
| async | 异步函数标识符 | 隐式返回 Promise |
| await | Promise 暂停器 | 仅限 async 函数内使用 |
掌握这些核心概念及其交互方式,可以编写出高效、可维护的异步 JavaScript 代码。
6️⃣ 参考 6
JavaScript 异步编程核心:Promise 与 async/await 完全指南
1. Promise 核心概念
- Promise 状态:
pending:初始状态fulfilled:操作成功完成rejected:操作失败
- 创建 Promise:
const promise = new Promise((resolve, reject) => { if (/* 成功条件 */) { resolve(value); // 状态变为 fulfilled } else { reject(error); // 状态变为 rejected } });
2. Promise 方法链
| 方法 | 作用 | 返回值 |
|---|---|---|
.then() | 处理成功状态 | 新 Promise |
.catch() | 捕获错误(推荐替代第二个参数) | 新 Promise |
.finally() | 无论成功失败都会执行(ES2018) | 新 Promise |
fetchData()
.then(processData) // 成功处理
.catch(handleError) // 错误捕获
.finally(cleanup); // 最终清理
3. async/await 语法糖
-
async函数:async function fetchUser() { return { name: "John" }; // 自动包装为 Promise }- 总是返回 Promise
- 普通值 →
Promise.resolve(value) - 抛出错误 →
Promise.reject(error)
-
await操作符:async function load() { const data = await fetchData(); // 暂停直到 Promise 完成 console.log(data); }- 只能在 async 函数内使用
- 暂停执行直到 Promise 完成
- 返回 Promise 的解决值
4. 错误处理对比
// Promise 方式
fetchData()
.then(handleSuccess)
.catch(handleError);
// async/await 方式
async function load() {
try {
const data = await fetchData();
handleSuccess(data);
} catch (err) {
handleError(err);
}
}
5. 执行流程控制
| 场景 | Promise 方案 | async/await 方案 |
|---|---|---|
| 顺序执行 | .then() 链 | 多个 await |
| 并行执行 | Promise.all() | await Promise.all() |
| 首个完成 | Promise.race() | await Promise.race() |
| 全部完成 | Promise.allSettled() | await Promise.allSettled() |
6. 关键特性对比
| 特性 | Promise | async/await |
|---|---|---|
| 代码结构 | 链式调用 | 同步风格 |
| 错误处理 | .catch() 方法 | try/catch 块 |
| 调试体验 | 异步堆栈跟踪 | 同步式堆栈跟踪 |
| 循环处理 | 需用 reduce 等技巧 | 直接使用循环语句 |
| 浏览器支持 | ES6+ (IE11+) | ES2017+ (现代浏览器) |
7. 最佳实践示例 并行请求优化:
// 高效并行
async function fetchAll() {
const [user, posts] = await Promise.all([
fetch('/user'),
fetch('/posts')
]);
return { user, posts };
}
循环处理:
// 正确方式:并行处理数组
async function processItems(items) {
const results = await Promise.all(
items.map(item => processItem(item))
);
return results;
}
最终清理:
async function transaction() {
let conn;
try {
conn = await db.connect();
const result = await conn.query('UPDATE...');
return result;
} catch (err) {
await conn.rollback();
throw err;
} finally {
conn?.release(); // 确保资源释放
}
}
8. 常见陷阱与解决方案
-
忘记 await
// 错误:返回 Promise 而非结果 async function getId() { return fetchId(); // 缺少 await! } -
循环中的顺序等待
// 低效:顺序执行 for (const url of urls) { await fetch(url); // 依次等待 } // 高效:并行执行 await Promise.all(urls.map(url => fetch(url))); -
异常穿透
// 错误:catch 无法捕获同步错误 async function load() { const data = await fetchData().catch(handleError); process(data); // 如果 process 抛错不会被捕获 } // 正确:使用完整 try/catch async function load() { try { const data = await fetchData(); process(data); } catch (err) { handleError(err); } } -
Promise 创建但未返回
// 错误:嵌套 Promise 未返回 async function save() { db.connect().then(conn => { return conn.query('INSERT...'); // 此 Promise 未传出 }); } // 正确:返回内部 Promise async function save() { return db.connect().then(conn => conn.query('INSERT...')); }
9. 浏览器兼容性解决方案
<!-- 旧浏览器支持 -->
<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.11/runtime.min.js"></script>
10. 选择指南
| 场景 | 推荐方案 |
|---|---|
| 简单异步操作 | Promise.then() |
| 复杂异步逻辑 | async/await |
| 多个独立异步操作 | Promise.all() |
| 资源清理(文件/数据库) | try/finally |
| 需要取消的操作 | Promise + AbortController |
核心原则:async/await 和 Promise 本质相通。async/await 让异步代码可读性更高,而 Promise 提供更底层的控制。现代项目中通常混合使用:async 函数内用 await 处理主要逻辑,用 .then() 处理简单副作用。
7️⃣ 参考 7
在 JavaScript 中,Promise、then/catch/finally 和 async/await 是处理异步操作的核心机制。下面我将系统性地解释这些概念,展示它们之间的关系和转换方法:
1. Promise 基础
Promise 是一个表示异步操作最终完成或失败的对象。它有三种状态:
- Pending:初始状态
- Fulfilled:操作成功完成
- Rejected:操作失败
const promise = new Promise((resolve, reject) => {
// 异步操作(如 API 请求、定时器等)
if (/* 成功 */) {
resolve(value); // 状态变为 fulfilled
} else {
reject(error); // 状态变为 rejected
}
});
2. then/catch/finally 方法 用于处理 Promise 的结果:
.then():处理成功状态(fulfilled).catch():处理失败状态(rejected).finally():无论成功失败都会执行(适合清理操作)
promise
.then(result => {
console.log("成功:", result);
})
.catch(error => {
console.error("失败:", error);
})
.finally(() => {
console.log("操作结束");
});
3. async/await 语法糖
async/await 是基于 Promise 的语法糖,使异步代码看起来像同步代码:
async:声明异步函数(隐式返回 Promise)await:暂停执行直到 Promise 完成(只能在 async 函数中使用)
async function fetchData() {
try {
const result = await promise; // 等待 Promise 完成
console.log("成功:", result);
} catch (error) {
console.error("失败:", error);
} finally {
console.log("操作结束");
}
}
关键概念对比表
| 特性 | Promise/then | async/await |
|---|---|---|
| 错误处理 | .catch() 方法 | try/catch 块 |
| 链式调用 | 多级 .then() 链 | 顺序同步写法 |
| 返回值 | 返回新 Promise | 隐式返回 Promise |
| 可读性 | 回调嵌套可能复杂 | 线性结构更清晰 |
| 并行处理 | Promise.all() | await Promise.all() |
相互转换示例
1. Promise → async/await
// 原始 Promise 链
function getUser() {
return fetch('/user')
.then(response => response.json())
.then(user => fetch(`/profile/${user.id}`))
.catch(error => console.error(error));
}
// 转换为 async/await
async function getUser() {
try {
const response = await fetch('/user');
const user = await response.json();
return await fetch(`/profile/${user.id}`);
} catch (error) {
console.error(error);
}
}
2. async/await → Promise
// 原始 async 函数
async function processOrder() {
const order = await fetchOrder();
await validate(order);
return send(order);
}
// 转换为 Promise 链
function processOrder() {
return fetchOrder()
.then(order => validate(order))
.then(() => send(order));
}
错误处理对比
// Promise 风格
fetchData()
.then(handleSuccess)
.catch(handleError) // 捕获链中所有错误
.finally(cleanup);
// async/await 风格
async function handleData() {
try {
const data = await fetchData();
handleSuccess(data);
} catch (err) {
handleError(err);
} finally {
cleanup();
}
}
高级用法
并行执行
// Promise.all + then
Promise.all([fetchUser(), fetchPosts()])
.then(([user, posts]) => render(user, posts));
// async/await 等效
async function loadAll() {
const [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);
render(user, posts);
}
finally 的特殊性
.finally() 不接收参数,且会透传原始结果:
promise
.finally(() => { /* 清理 */ })
.then(result => {
// 仍能获得原始 promise 的结果
});
关键注意事项
-
await 只能在 async 函数中使用
// 错误示例 function syncFunc() { const data = await fetchData(); // SyntaxError } -
async 函数始终返回 Promise
async function foo() { return 42; } foo().then(result => console.log(result)); // 42 -
错误未捕获会导致全局错误
// 未处理的 Promise 拒绝 fetchData().then(); // 缺少 catch -
避免过度顺序化
// 低效写法(顺序等待) const a = await fetchA(); // 先等 A 完成 const b = await fetchB(); // 再等 B 开始 // 高效写法(并行执行) const [a, b] = await Promise.all([fetchA(), fetchB()]); -
await 可以接收非 Promise 值
async function example() { const num = await 42; // 等同于 Promise.resolve(42) }
通过理解这些概念和转换模式,你可以根据场景灵活选择最合适的异步处理方式。现代 JavaScript 开发中通常优先使用 async/await 提升可读性,但在需要精细控制时仍会结合使用原始 Promise API。
8️⃣ 参考 8
JavaScript 异步编程完全指南:Promise, then, catch, finally, async, await
一、核心概念全景图
graph TD
A[异步操作] --> B[Promise]
B --> C[then]
B --> D[catch]
B --> E[finally]
B --> F[async/await]
C --> G[链式调用]
D --> H[错误处理]
E --> I[清理操作]
F --> J[同步风格]
G --> K[顺序执行]
J --> L[try/catch]
二、Promise 核心机制
1. Promise 状态生命周期
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
Math.random() > 0.5 ?
resolve('成功数据') :
reject(new Error('失败原因'));
}, 1000);
});
// 状态变化:
// pending → fulfilled (成功)
// pending → rejected (失败)
2. Promise 静态方法
| 方法 | 描述 | 示例 |
|---|---|---|
Promise.resolve() | 创建已解决的 Promise | Promise.resolve(42) |
Promise.reject() | 创建已拒绝的 Promise | Promise.reject(error) |
Promise.all() | 所有成功或一个失败 | Promise.all([p1, p2]) |
Promise.race() | 第一个解决或拒绝 | Promise.race([p1, p2]) |
Promise.allSettled() | 所有解决或拒绝 | Promise.allSettled([p1, p2]) |
Promise.any() | 第一个成功解决 | Promise.any([p1, p2]) |
三、then/catch/finally 深度解析
1. 链式调用模式
fetch('/api/data')
.then(response => {
if (!response.ok) throw new Error('网络响应错误');
return response.json();
})
.then(data => {
console.log('数据:', data);
return processData(data);
})
.then(processed => {
saveData(processed);
})
.catch(error => {
console.error('请求失败:', error);
return getCachedData();
})
.finally(() => {
hideLoadingSpinner();
});
2. 错误处理策略对比
| 方式 | 特点 | 最佳场景 |
|---|---|---|
then 第二个参数 | 局部错误处理 | 特定步骤的错误恢复 |
catch | 全局错误捕获 | 链式调用的错误兜底 |
try/catch | 同步风格处理 | async/await 环境 |
四、async/await 革命性语法
1. 基本用法
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTP错误! 状态码: ${response.status}`);
}
const user = await response.json();
const posts = await fetchUserPosts(user.id);
return { user, posts };
} catch (error) {
console.error('获取用户数据失败:', error);
return { user: null, posts: [] };
} finally {
console.log('用户数据请求完成');
}
}
2. 并行执行优化
async function loadDashboard() {
// 并行启动所有请求
const [userPromise, postsPromise, statsPromise] = [
fetchUser(),
fetchPosts(),
fetchStats()
];
// 顺序等待结果
const user = await userPromise;
const posts = await postsPromise;
const stats = await statsPromise;
// 处理数据
return {
user,
posts: filterPosts(posts, user.preferences),
stats: calculateMetrics(stats)
};
}
五、混合使用模式与转换
1. Promise 链 → async/await 转换
// Promise 链
function processOrder() {
return validateOrder()
.then(order => chargePayment(order))
.then(receipt => shipProducts(receipt))
.catch(error => handleError(error));
}
// async/await 等效
async function processOrder() {
try {
const order = await validateOrder();
const receipt = await chargePayment(order);
return await shipProducts(receipt);
} catch (error) {
return handleError(error);
}
}
2. async/await → Promise 转换
// async/await 版本
async function getUserReports(userId) {
const user = await getUser(userId);
const reports = await getReports(user.department);
return processReports(user, reports);
}
// Promise 链等效
function getUserReports(userId) {
return getUser(userId)
.then(user => getReports(user.department))
.then(reports => processReports(user, reports));
}
六、高级异步模式
1. 超时控制实现
function withTimeout(promise, timeoutMs, timeoutError = new Error('超时')) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(timeoutError), timeoutMs)
]);
}
// 使用
async function fetchWithTimeout() {
try {
const data = await withTimeout(
fetch('/api/data'),
5000,
new Error('请求超时')
);
return data.json();
} catch (error) {
if (error.message === '请求超时') {
return getCachedData();
}
throw error;
}
}
2. 自动重试机制
async function retry(fn, retries = 3, delay = 1000) {
try {
return await fn();
} catch (error) {
if (retries <= 0) throw error;
await new Promise(res => setTimeout(res, delay));
return retry(fn, retries - 1, delay * 2); // 指数退避
}
}
// 使用
async function fetchData() {
return retry(() => fetch('/api/unstable'), 5);
}
3. 并发控制
async function runParallel(tasks, concurrency = 5) {
const results = [];
const executing = [];
for (const task of tasks) {
const p = task().then(result => {
executing.splice(executing.indexOf(p), 1);
return result;
});
results.push(p);
executing.push(p);
if (executing.length >= concurrency) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
// 使用
async function processImages(images) {
const tasks = images.map(img => () => processImage(img));
return runParallel(tasks, 3); // 最大并发3
}
七、错误处理最佳实践
1. 分层错误处理
async function mainWorkflow() {
try {
// 核心业务逻辑
const input = await loadInput();
const processed = await processData(input);
await saveResults(processed);
} catch (error) {
// 业务逻辑错误处理
if (error instanceof ValidationError) {
await logValidationError(error);
return { status: 'invalid' };
}
if (error instanceof NetworkError) {
await retryOperation();
return { status: 'retrying' };
}
// 无法处理的错误重新抛出
throw error;
}
}
// 顶层调用
mainWorkflow()
.then(result => console.log('完成:', result))
.catch(error => {
// 全局兜底错误处理
console.error('未处理的错误:', error);
sendErrorToMonitoring(error);
process.exit(1);
});
2. 错误类型化
class AppError extends Error {
constructor(message, code) {
super(message);
this.code = code;
this.name = this.constructor.name;
}
}
class ApiError extends AppError {
constructor(endpoint, status) {
super(`${endpoint} 请求失败`, 'API_ERROR');
this.status = status;
}
}
// 使用
async function fetchResource() {
try {
const res = await fetch('/api/resource');
if (!res.ok) throw new ApiError('/api/resource', res.status);
return res.json();
} catch (error) {
if (error instanceof ApiError && error.status === 404) {
return getFallbackData();
}
throw error;
}
}
八、性能优化策略
1. 避免阻塞事件循环
// 错误:阻塞主线程
async function processLargeArray(array) {
const results = [];
for (const item of array) {
// 同步CPU密集型操作
const result = cpuIntensiveTask(item);
results.push(result);
}
return results;
}
// 正确:使用任务分割
async function processLargeArray(array) {
const CHUNK_SIZE = 1000;
const results = [];
for (let i = 0; i < array.length; i += CHUNK_SIZE) {
const chunk = array.slice(i, i + CHUNK_SIZE);
// 使用setTimeout释放事件循环
await new Promise(resolve => setTimeout(resolve, 0));
results.push(...processChunk(chunk));
}
return results;
}
2. 内存管理
async function processStream() {
const stream = getDataStream();
let buffer = [];
for await (const chunk of stream) {
buffer.push(chunk);
if (buffer.length >= 1000) {
await processBatch(buffer);
buffer = []; // 清除引用,防止内存泄漏
}
}
if (buffer.length > 0) {
await processBatch(buffer);
}
}
九、现代异步编程全景图
1. 进化历程
回调函数 → Promise → Generator → async/await → 顶层await
2. 技术选型指南
| 场景 | 推荐方案 | 示例 |
|---|---|---|
| 简单异步 | Promise.then | fetch(url).then(r => r.json()) |
| 复杂流程 | async/await | 包含条件/循环的异步逻辑 |
| 并行操作 | Promise.all | 同时发起多个独立请求 |
| 错误恢复 | catch + 条件判断 | 特定错误类型恢复 |
| 资源清理 | finally | 关闭文件/数据库连接 |
| 浏览器环境 | async/await + try/catch | 前端应用逻辑 |
| Node.js 流 | for-await-of | 处理大文件流 |
3. 终极实践模板
async function robustAsyncOperation(params) {
try {
// 1. 准备阶段
const config = await loadConfig();
// 2. 并行获取数据
const [primaryData, secondaryData] = await Promise.all([
fetchPrimaryData(config),
fetchSecondaryData(config)
]);
// 3. 处理数据
const processed = processData(primaryData, secondaryData);
// 4. 保存结果
await saveResult(processed);
// 5. 返回成功
return { status: 'success', data: processed };
} catch (error) {
// 错误分类处理
if (error instanceof NetworkError) {
console.warn('网络错误,使用缓存数据');
return { status: 'cached', data: getCachedData() };
}
if (error instanceof ValidationError) {
console.error('数据验证失败:', error.details);
throw new CriticalError('INVALID_DATA', error);
}
// 未知错误
console.error('未知错误:', error);
throw error;
} finally {
// 资源清理
releaseResources();
trackOperationEnd();
}
}
十、未来趋势
1. 顶层 await (ES2022)
// 模块顶层直接使用 await
const data = await fetchConfig();
export default processData(data);
2. Promise.withResolvers (ES2024)
const { promise, resolve, reject } = Promise.withResolvers();
setTimeout(() => {
resolve('成功结果');
}, 1000);
await promise;
3. 异步上下文
// 实验性特性
const asyncContext = new AsyncContext();
async function main() {
asyncContext.set('requestId', generateId());
await fetchData(); // 所有异步操作共享上下文
await processData();
console.log('请求ID:', asyncContext.get('requestId'));
}
总结
JavaScript 异步编程的核心要点:
- Promise 是基础:所有现代异步操作的基石
- then/catch/finally 链式调用:提供顺序执行、错误处理和清理机制
- async/await 革命:用同步方式写异步代码,提升可读性
- 错误处理是关键:分层处理、类型化错误和全局兜底
- 性能优化不可忽视:并行执行、流处理和内存管理
- 混合使用更强大:根据场景选择最佳组合模式
graph LR
A[异步操作] --> B[Promise]
B --> C[.then]
B --> D[.catch]
B --> E[.finally]
B --> F[async]
F --> G[await]
C --> H[链式调用]
D --> I[错误处理]
E --> J[清理操作]
G --> K[同步风格]
H --> L[顺序执行]
K --> M[try/catch]
I --> N[错误恢复]
J --> O[资源释放]
掌握这些异步编程技术,能让你构建更健壮、高效和可维护的 JavaScript 应用程序。无论是浏览器端还是 Node.js 环境,这些核心概念都是现代 JavaScript 开发者的必备技能。
9️⃣ 参考 9
在 JavaScript 中,Promise 和 async/await 是处理异步操作的两种核心机制。下面我将系统化地解释这些概念及其相互关系:
1. Promise 基础 Promise 对象表示异步操作的最终完成(或失败)及其结果值。
const promise = new Promise((resolve, reject) => {
// 异步操作(如 API 请求)
setTimeout(() => {
Math.random() > 0.5
? resolve("成功数据")
: reject("错误原因")
}, 1000);
});
2. Promise 方法链 .then() - 处理成功状态
promise.then(result => {
console.log("成功:", result);
});
.catch() - 处理失败状态
promise.catch(error => {
console.error("失败:", error);
});
.finally() - 无论成功失败都执行
promise.finally(() => {
console.log("操作结束");
});
链式调用示例
fetch("/api/data")
.then(response => response.json())
.then(data => processData(data))
.catch(error => handleError(error))
.finally(() => cleanUp());
3. async/await 语法糖 基于 Promise 的语法扩展,使异步代码看起来像同步代码。
async 函数声明
async function fetchData() {
// 函数始终返回 Promise
}
await 操作符
async function getUser() {
try {
const response = await fetch("/api/user"); // 暂停执行直到 Promise 解决
const data = await response.json();
return data;
} catch (error) {
console.error(error);
}
}
4. 关键差异对比
| 特性 | Promise 链 | async/await |
|---|---|---|
| 可读性 | 回调嵌套可能复杂 | 顺序执行,类似同步代码 |
| 错误处理 | .catch() 方法 | try/catch 块 |
| 调试 | 难追踪链式调用 | 支持同步式断点调试 |
| 返回值 | 必须返回新 Promise | 自动包装为 Promise |
| 循环处理 | 需用 Promise.all 等组合 | 可直接用 for 循环 |
5. 相互转换规则 Promise → async/await
// 原始
function loadData() {
return fetchData()
.then(process)
.catch(handleError);
}
// 转换后
async function loadData() {
try {
const data = await fetchData();
return process(data);
} catch (err) {
handleError(err);
}
}
async/await → Promise
// 原始
async function calculate() {
const a = await getA();
const b = await getB();
return a + b;
}
// 转换后
function calculate() {
return getA()
.then(a => getB().then(b => a + b));
}
6. 高级模式 并行执行优化
// 顺序执行 (慢)
async function sequential() {
const a = await task(1000);
const b = await task(2000); // 等待前一个完成
}
// 并行执行 (快)
async function parallel() {
const [a, b] = await Promise.all([
task(1000),
task(2000) // 同时启动
]);
}
错误处理模式对比
// Promise 链错误穿透
fetchData()
.then()
.then()
.catch() // 捕获前面所有错误
// async/await 局部捕获
async function process() {
try {
const a = await step1();
} catch (err) {
handleStep1Error(err); // 仅捕获 step1 错误
}
const b = await step2(); // 继续执行
}
7. 关键注意事项
-
避免 await 滥用:
// 反模式 - 不必要的串行 const a = await getA(); // 等待 1s const b = await getB(); // 再等待 1s (总 2s) // 正确并行 const [a, b] = await Promise.all([getA(), getB()]); // 总 1s -
返回 await 的特殊情况:
async function foo() { return await bar(); // 与 return bar() 的区别: // 1. 会等待 bar() 的微任务 // 2. 能在 try/catch 中捕获错误 } -
Promise 构造函数反模式:
// 错误:将 async 函数包装在 new Promise 中 const promise = new Promise(async (resolve, reject) => { try { const data = await fetchData(); // 可能导致未处理错误 resolve(data); } catch (err) { reject(err); } }); // 正确:直接使用 async 函数 const promise = fetchData(); // 自动返回 Promise
总结
| 概念 | 用途 |
|---|---|
Promise | 异步操作的容器,提供标准化管理接口 |
.then() | 处理 Promise 成功状态 |
.catch() | 处理 Promise 失败状态 |
.finally() | 无论成功失败都执行的清理逻辑 |
async | 声明异步函数,使其隐式返回 Promise |
await | 暂停 async 函数执行,等待 Promise 解决 |
选择原则:
- 简单链式调用 → Promise 链
- 复杂异步逻辑 → async/await
- 并行任务 →
Promise.all/Promise.race配合 await
🔟 参考 10
JavaScript 异步编程:Promise 与 async/await 深度解析
JavaScript 的异步编程经历了从回调地狱到 Promise,再到 async/await 的演变。下面我将全面解析这些核心概念及其关系。
核心概念一览
| 概念 | 描述 | 使用场景 |
|---|---|---|
| Promise | 表示异步操作的最终结果 | 所有异步操作的基础 |
| then() | 处理 Promise 成功状态 | 链式调用异步操作 |
| catch() | 处理 Promise 失败状态 | 错误处理 |
| finally() | 无论成功失败都会执行 | 清理操作 |
| async | 声明异步函数 | 创建支持 await 的函数 |
| await | 等待 Promise 解决 | 在 async 函数中暂停执行 |
1. Promise:异步操作的容器
Promise 是一个表示异步操作最终结果的对象,有三种状态:
- pending:初始状态
- fulfilled:操作成功完成
- rejected:操作失败
// 创建 Promise
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = Math.random() > 0.5;
success ? resolve("操作成功!") : reject("操作失败!");
}, 1000);
});
2. then():处理成功状态
then() 方法用于处理 Promise 的解决值:
promise.then(
result => {
console.log("成功:", result);
return result.toUpperCase(); // 返回值将包装为新 Promise
},
error => {
console.error("失败:", error);
throw new Error("处理错误"); // 抛出错误将进入 catch
}
);
3. catch():处理错误状态
专门处理 Promise 链中的错误:
promise
.then(result => {
console.log(result);
throw new Error("处理中出错"); // 模拟错误
})
.catch(error => {
console.error("捕获错误:", error.message);
return "错误已处理"; // 恢复执行
});
4. finally():清理操作
无论成功失败都会执行,适合清理资源:
let isLoading = true;
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("请求失败", error))
.finally(() => {
isLoading = false;
console.log("请求结束");
});
5. async:声明异步函数
async 函数总是返回 Promise:
async function fetchUser(userId) {
if (!userId) throw new Error("缺少用户ID");
return { id: userId, name: "张三" };
}
// 等效于:
function fetchUser(userId) {
return new Promise((resolve, reject) => {
if (!userId) reject(new Error("缺少用户ID"));
resolve({ id: userId, name: "张三" });
});
}
6. await:暂停执行等待 Promise
只能在 async 函数内部使用:
async function getUserDetails(userId) {
try {
console.log("开始获取用户数据...");
const user = await fetchUser(userId); // 暂停直到 Promise 解决
console.log("开始获取用户订单...");
const orders = await fetchOrders(user.id);
return { ...user, orders };
} catch (error) {
console.error("获取用户详情失败:", error);
return null;
} finally {
console.log("用户详情获取流程结束");
}
}
Promise 与 async/await 转换
Promise.then → async/await
// Promise 链
function loadData() {
return fetchData()
.then(processData)
.then(saveData)
.catch(handleError);
}
// async/await 等效
async function loadData() {
try {
const rawData = await fetchData();
const processed = await processData(rawData);
return await saveData(processed);
} catch (error) {
handleError(error);
}
}
async/await → Promise.then
// async/await
async function calculate() {
const a = await getValueA();
const b = await getValueB();
return a + b;
}
// Promise 链等效
function calculate() {
return getValueA()
.then(a => getValueB().then(b => a + b));
}
高级模式与最佳实践
1. 并行执行
// 顺序执行 - 慢
async function sequential() {
const user = await fetchUser();
const posts = await fetchPosts(user.id);
return { user, posts };
}
// 并行执行 - 快
async function parallel() {
const [user, posts] = await Promise.all([
fetchUser(),
fetchPosts()
]);
return { user, posts };
}
2. 错误处理策略
// 方式1:try/catch(推荐)
async function safeFetch() {
try {
const response = await fetch(url);
return response.json();
} catch (error) {
console.error("请求失败:", error);
return null;
}
}
// 方式2:catch() 方法
async function safeFetch() {
const response = await fetch(url).catch(error => {
console.error("请求失败:", error);
return null;
});
return response?.json();
}
// 方式3:混合模式
async function main() {
const data = await fetchData().catch(handleError);
if (!data) return;
// 处理数据...
}
3. Promise 工具方法
// 任意一个成功
const firstSuccess = await Promise.any([
fetchFromSourceA(),
fetchFromSourceB()
]);
// 等待所有完成(无论成功失败)
const allResults = await Promise.allSettled([
updateProfile(),
savePreferences()
]);
4. 避免常见陷阱
// 错误:在循环中顺序等待
async function slowProcess(items) {
for (const item of items) {
await processItem(item); // 每次循环等待完成
}
}
// 正确:并行处理
async function fastProcess(items) {
await Promise.all(items.map(processItem));
}
// 错误:忘记 await
async function getData() {
const promise = fetchData(); // 缺少 await
console.log(promise); // 输出 Promise 对象而非结果
}
浏览器兼容性与现代用法
所有现代浏览器(Chrome、Firefox、Safari、Edge)和 Node.js(v7.6+)都原生支持这些特性。对于旧环境,可通过 Babel 转译。
顶级 await(ES2022)
现代环境支持在模块顶层使用 await:
// 模块中直接使用
const data = await fetchData();
console.log(data);
总结对比
| 特性 | Promise.then | async/await |
|---|---|---|
| 代码结构 | 链式调用 | 线性同步风格 |
| 可读性 | 中等 | 高 |
| 错误处理 | .catch() | try/catch |
| 调试体验 | 一般 | 优秀 |
| 流程控制 | 需要手动组合 | 更直观 |
最佳实践建议:
- 新项目优先使用 async/await
- 简单操作可使用 Promise.then
- 并行任务使用 Promise.all/Promise.any
- 始终处理可能的错误
- 使用 finally 进行资源清理
graph TD
A[异步操作] --> B{Promise}
B -->|成功| C[then]
B -->|失败| D[catch]
C & D --> E[finally]
F[async函数] --> G[await Promise]
G --> H[处理结果]
G --> I[捕获错误]
H & I --> J[返回新Promise]
掌握这些核心概念,你将能够编写更清晰、更健壮的异步 JavaScript 代码!
🤔 参考 11
JavaScript 异步编程终极指南:Promise 与 async/await
一、Promise 核心体系
1. Promise 基础
- 本质:表示异步操作的容器
- 状态:
pending(等待中)fulfilled(已成功)rejected(已失败)
- 不可逆:状态一旦改变不可回退
// 创建 Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.5
? resolve("成功!")
: reject(new Error("失败!"));
}, 1000);
});
2. Promise 链式方法
.then(onFulfilled, onRejected)
- 处理成功状态(核心方法)
- 返回新 Promise 支持链式调用
- 值穿透:未提供回调时直接传递值
fetchData()
.then(data => {
console.log("第一步:", data);
return process(data); // 返回新值/Promise
})
.then(processed => {
console.log("第二步:", processed);
});
.catch(onRejected)
- 专门处理拒绝状态
- 本质是
.then(null, onRejected)的语法糖 - 捕获链中所有未处理的错误
apiCall()
.then(handleSuccess)
.catch(error => {
console.error("全局捕获:", error);
return fallbackValue; // 提供恢复值
});
.finally(onFinally)
- 无论成功失败都会执行
- 不接收参数,不影响最终值
- 最适合执行清理操作
let loading = true;
fetchResource()
.then(data => save(data))
.catch(logError)
.finally(() => {
loading = false; // 清理状态
console.log("请求结束");
});
3. 静态方法
| 方法 | 描述 | 示例 |
|---|---|---|
Promise.resolve() | 创建已解决的 Promise | Promise.resolve(42) |
Promise.reject() | 创建已拒绝的 Promise | Promise.reject(error) |
Promise.all() | 所有成功时返回结果数组 | Promise.all([p1, p2]) |
Promise.race() | 返回最先完成的 Promise | Promise.race([req, timeout]) |
Promise.allSettled() | 所有完成后返回状态数组 | Promise.allSettled([p1, p2]) |
Promise.any() | 任一成功即返回结果 | Promise.any([p1, p2]) |
二、async/await 革命
1. async 函数
- 声明:函数前添加
async关键字 - 返回值:总是返回 Promise 对象
- 返回非 Promise → 包装为 resolved Promise
- 抛出错误 → 返回 rejected Promise
async function getUser() {
return { id: 1, name: "John" }; // 自动包装为Promise
}
// 等价于
function getUser() {
return Promise.resolve({ id: 1, name: "John" });
}
2. await 表达式
- 作用:暂停 async 函数执行,等待 Promise 解决
- 规则:
- 只能在 async 函数内部使用
- 返回 Promise 的解决值
- 遇到 rejection 抛出异常
async function fetchData() {
try {
const response = await fetch('/api/data'); // 暂停等待
const data = await response.json(); // 再次等待
return data;
} catch (error) {
console.error("请求失败:", error);
}
}
三、混合应用模式
1. 错误处理策略
// 混合错误处理
async function robustFetch() {
try {
const response = await fetch('/data').catch(handleNetworkError);
if (!response.ok) {
throw new Error('API响应错误');
}
return response.json();
} catch (error) {
if (error instanceof TypeError) {
return cachedData();
}
throw error;
}
}
2. 并行优化技巧
async function loadDashboard() {
// 并行启动请求
const userPromise = fetchUser();
const ordersPromise = fetchOrders();
// 顺序处理依赖数据
const user = await userPromise;
const recommendations = await getRecommendations(user.id);
// 等待并行结果
const [orders] = await Promise.all([ordersPromise]);
return { user, orders, recommendations };
}
3. 循环控制模式
// 顺序执行
async function processQueue(tasks) {
for (const task of tasks) {
await task.execute(); // 顺序执行
}
}
// 并行执行(控制并发数)
async function parallelProcess(tasks, concurrency = 5) {
const results = [];
for (let i = 0; i < tasks.length; i += concurrency) {
const batch = tasks.slice(i, i + concurrency);
const batchResults = await Promise.all(
batch.map(task => task.execute())
);
results.push(...batchResults);
}
return results;
}
四、最佳实践指南
1. 错误处理黄金法则
// 推荐:async/await + try/catch
async function safeOperation() {
try {
const result = await riskyOperation();
return process(result);
} catch (error) {
if (error instanceof SpecificError) {
return handleSpecificError(error);
}
logger.error(error);
throw new AppError('操作失败', { cause: error });
} finally {
cleanupResources();
}
}
// Promise等效实现
function safeOperationPromise() {
return riskyOperation()
.then(process)
.catch(error => {
if (error instanceof SpecificError) {
return handleSpecificError(error);
}
logger.error(error);
return Promise.reject(new AppError('操作失败', { cause: error }));
})
.finally(cleanupResources);
}
2. 性能优化策略
| 模式 | 反例 | 正例 |
|---|---|---|
| 并行请求 | const a = await getA(); const b = await getB(); | const [a, b] = await Promise.all([getA(), getB()]) |
| 提前启动 | await a; await b; | const a = getA(); const b = getB(); await a; await b; |
| 缓存请求 | 每次重新请求 | 使用内存/缓存存储Promise |
3. 常见陷阱及解决方案
-
忘记await
// 错误 async function saveData() { const data = fetchData(); // 返回Promise而不是数据 store.save(data); // 保存的是Promise对象 } // 正确 async function saveData() { const data = await fetchData(); store.save(data); } -
异常吞噬
// 危险:未处理的拒绝 async function dangerous() { const promise = fetchData(); // 缺少await // 如果fetchData拒绝,会产生未处理的拒绝 } // 安全方案 async function safe() { const promise = fetchData().catch(logError); // 添加错误处理 // 或 try { const data = await fetchData(); } catch (error) {/*...*/} } -
循环中的并发失控
// 危险:可能创建数万个并发请求 async function massRequests() { const urls = [/* 大量URL */]; const results = await Promise.all(urls.map(fetch)); } // 安全:限制并发数 import pLimit from 'p-limit'; async function controlledRequests() { const limit = pLimit(10); // 最大并发数 const urls = [/* 大量URL */]; const promises = urls.map(url => limit(() => fetch(url)) ); return Promise.all(promises); }
五、高级应用场景
1. 取消机制实现
function cancellablePromise(executor) {
let rejectFn;
const promise = new Promise((resolve, reject) => {
rejectFn = reject;
executor(resolve, reject);
});
return {
promise,
cancel: (reason = "已取消") => rejectFn(new CancellationError(reason))
};
}
// 使用示例
const { promise, cancel } = cancellablePromise(resolve => {
setTimeout(() => resolve("完成"), 5000);
});
// 用户取消操作
cancelButton.addEventListener('click', () => cancel("用户取消"));
2. 进度跟踪
function trackablePromise(executor) {
const progressHandlers = [];
const promise = new Promise((resolve, reject) => {
executor(
resolve,
reject,
progress => {
progressHandlers.forEach(handler => handler(progress));
}
);
});
return {
promise,
onProgress: handler => {
progressHandlers.push(handler);
return this;
}
};
}
// 使用示例
const fileUpload = trackablePromise((resolve, reject, progress) => {
// 模拟上传进度
let percent = 0;
const interval = setInterval(() => {
percent += 10;
progress(percent);
if (percent >= 100) {
clearInterval(interval);
resolve();
}
}, 500);
});
fileUpload.onProgress(p => console.log(`${p}%`))
.promise
.then(() => console.log("上传完成"));
六、浏览器支持与兼容方案
1. 支持情况
| 特性 | 浏览器支持 | Node.js 支持 |
|---|---|---|
| Promise | Chrome 32+, FF 29+, ES6+ | Node 0.12+ |
| async/await | Chrome 55+, FF 52+, ES8+ | Node 7.6+ |
| finally | Chrome 63+, FF 58+, ES10 | Node 10+ |
| allSettled | Chrome 76+, FF 71+, ES11 | Node 12.9+ |
2. 兼容方案
<!-- 旧浏览器支持 -->
<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/regenerator-runtime@0.13.11/runtime.min.js"></script>
<!-- Babel 转译 async/await -->
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
// async/await 代码
</script>
七、总结:选择指南
-
简单异步操作:直接使用 Promise
fetchData() .then(process) .catch(handleError); -
复杂异步流程:首选 async/await
async function complexFlow() { try { const a = await step1(); const b = await step2(a); return await step3(b); } catch (error) { handleError(error); } } -
并行处理:Promise.all + async/await
async function parallelTasks() { const [res1, res2] = await Promise.all([task1(), task2()]); // 处理结果 } -
终极建议:
graph TD A[开始异步操作] --> B{简单单步?} B -->|是| C[使用Promise.then] B -->|否| D{需要并行?} D -->|是| E[Promise.all + async/await] D -->|否| F[纯async/await] C --> G[结束] E --> G F --> G
掌握 Promise 和 async/await 的组合使用,能够让你编写出既高效又易维护的异步 JavaScript 代码,彻底告别回调地狱,构建现代化的 Web 应用。
🤔 参考 12
在 JavaScript 中,Promise、then/catch/finally 和 async/await 是处理异步操作的核心机制。以下是它们的详细解释和相互关系:
1. Promise(承诺) Promise 对象表示一个异步操作的最终完成(或失败)及其结果值。
const promise = new Promise((resolve, reject) => {
// 异步操作(如 API 请求、定时器等)
if (/* 成功 */) resolve("Success!"); // 状态变为 fulfilled
else reject("Error!"); // 状态变为 rejected
});
三种状态:
pending:初始状态fulfilled:操作成功完成rejected:操作失败
2. .then() / .catch() / .finally() Promise 的链式调用方法: .then() - 处理成功状态
promise.then(
result => console.log(result), // 成功时执行
error => console.error(error) // 失败时执行(可选)
);
.catch() - 专门处理错误
promise
.then(result => console.log(result))
.catch(error => console.error("Caught:", error)); // 捕获所有错误
.finally() - 无论成功失败都会执行
promise
.then(/* ... */)
.catch(/* ... */)
.finally(() => console.log("Cleanup")); // 如关闭加载动画
3. async / await(语法糖) 基于 Promise 的语法糖,使异步代码看起来像同步代码。
async 函数
- 总是返回一个 Promise
- 允许在函数内使用
await
async function fetchData() {
return "Data"; // 自动包装为 Promise.resolve("Data")
}
await 表达式
- 暂停 async 函数的执行,等待 Promise 解决
- 只能在 async 函数中使用
async function getUser() {
try {
const response = await fetch("/api/user"); // 等待 Promise 解决
const data = await response.json(); // 再次等待
return data;
} catch (error) {
console.error("Failed:", error);
}
}
4. 核心关系
graph LR
A[Promise] --> B[.then/.catch/.finally]
A --> C[async/await]
B -->|底层机制| C
C -->|语法糖| B
- Promise 是基础:所有异步操作的核心
- .then/.catch/.finally:直接操作 Promise 的方法
- async/await:基于 Promise 的语法糖,更易读写
5. 关键对比
| 特性 | Promise 链 | async/await |
|---|---|---|
| 可读性 | 回调嵌套较复杂 | 类似同步代码,更清晰 |
| 错误处理 | .catch() 链式捕获 | try/catch 块捕获 |
| 调试 | 回调中断点难追踪 | 支持同步式断点调试 |
| 返回值 | 返回新 Promise | 隐式返回 Promise |
| 并行处理 | Promise.all() | await Promise.all() |
6. 最佳实践示例 组合使用
// 并行请求 + 错误处理
async function fetchAll() {
try {
const [users, posts] = await Promise.all([
fetch("/users"),
fetch("/posts")
]);
return { users, posts };
} catch (error) {
console.error("Parallel fetch failed:", error);
throw error; // 重新抛出错误
} finally {
console.log("Request completed");
}
}
// 调用
fetchAll()
.then(data => console.log(data))
.catch(err => console.error("Global catch:", err));
避免常见陷阱
// ❌ 错误:顺序等待(应并行)
async function slowFetch() {
const a = await fetchA(); // 等待完成
const b = await fetchB(); // 再开始(效率低)
}
// ✅ 正确:并行请求
async function fastFetch() {
const [a, b] = await Promise.all([fetchA(), fetchB()]);
}
// ❌ 错误:忘记 await
async function oops() {
const data = fetchData(); // 返回 Promise 而非实际数据
console.log(data); // 输出 Promise 对象
}
7. 执行顺序图解
console.log("Start");
setTimeout(() => console.log("Timeout"), 0);
Promise.resolve("Promise")
.then(res => console.log(res));
async function test() {
console.log("Async start");
await Promise.resolve();
console.log("Async end");
}
test();
console.log("End");
/* 输出顺序:
Start
Async start
End
Promise // 微任务优先于宏任务
Async end
Timeout
*/
执行规则:
- 同步代码 > 微任务(Promise.then) > 宏任务(setTimeout)
await后的代码相当于.then()回调(微任务)
总结
- Promise:异步操作的容器
- .then/.catch/.finally:直接操作 Promise 的方法
- async/await:基于 Promise 的语法糖,简化异步流程控制
- 优先使用 async/await:提高代码可读性
- 保留 Promise 知识:用于底层优化和特殊场景(如
Promise.race())
🤔 参考 13
JavaScript 异步编程全面解析:Promise 与 async/await
下面我将详细讲解 JavaScript 中的 Promise、then、catch、finally、async 和 await 这些核心异步编程概念,并提供实用示例。
1. Promise(承诺)
Promise 是 JavaScript 中处理异步操作的核心对象,代表一个异步操作的最终完成(或失败)及其结果值。
基本结构:
const myPromise = new Promise((resolve, reject) => {
// 异步操作(如 API 请求、定时器等)
if (/* 操作成功 */) {
resolve('成功数据'); // 将 Promise 状态改为 fulfilled
} else {
reject('错误原因'); // 将 Promise 状态改为 rejected
}
});
Promise 的三种状态:
- pending:初始状态
- fulfilled:操作成功完成
- rejected:操作失败
2. .then() 方法
.then() 用于处理 Promise 的完成状态(fulfilled):
myPromise.then(
(result) => {
console.log('成功:', result);
},
(error) => {
console.error('失败:', error);
}
);
链式调用:
fetchData()
.then(processData)
.then(saveData)
.then(finalize);
3. .catch() 方法
.catch() 专门用于捕获 Promise 链中的错误:
fetchData()
.then(processData)
.then(saveData)
.catch(error => {
console.error('处理过程中出错:', error);
return fallbackData(); // 提供回退方案
});
4. .finally() 方法
.finally() 无论 Promise 成功还是失败都会执行,适合清理操作:
let isLoading = true;
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error))
.finally(() => {
isLoading = false; // 无论成功失败都会执行
console.log('请求结束');
});
5. async/await
async/await 是基于 Promise 的语法糖,使异步代码看起来像同步代码。
async 函数:
async function fetchUserData() {
// 函数始终返回 Promise
return { name: 'John', age: 30 };
}
// 等同于:
function fetchUserData() {
return Promise.resolve({ name: 'John', age: 30 });
}
await 表达式:
async function getUser() {
try {
const response = await fetch('/api/user'); // 暂停执行直到 Promise 完成
const data = await response.json(); // 再次等待
console.log(data);
return data;
} catch (error) {
console.error('获取用户失败:', error);
}
}
6. 综合使用示例
用户认证流程:
async function authenticateUser(username, password) {
try {
// 1. 验证输入
if (!username || !password) {
throw new Error('用户名和密码不能为空');
}
// 2. 获取用户数据
const user = await fetchUser(username);
// 3. 验证密码
const isValid = await validatePassword(user, password);
if (!isValid) {
throw new Error('密码错误');
}
// 4. 生成访问令牌
const token = await generateToken(user);
return { success: true, token };
} catch (error) {
console.error('认证失败:', error.message);
return { success: false, error: error.message };
} finally {
// 5. 清理资源(无论成功失败都执行)
cleanUpResources();
}
}
// 使用示例
authenticateUser('john_doe', 'secure123')
.then(result => {
if (result.success) {
console.log('认证成功,令牌:', result.token);
} else {
console.log('认证失败:', result.error);
}
});
7. 最佳实践与常见模式
并行操作优化:
async function loadDashboard() {
// 同时发起三个并行请求
const [user, orders, notifications] = await Promise.all([
fetchUser(),
fetchOrders(),
fetchNotifications()
]);
return { user, orders, notifications };
}
错误处理模式:
// 方法1:try/catch
async function fetchData() {
try {
const data = await apiCall();
return data;
} catch (error) {
// 处理错误
}
}
// 方法2:catch() 方法
async function fetchData() {
const data = await apiCall().catch(error => {
// 处理错误
return fallbackData;
});
return data;
}
循环中的异步操作:
// 顺序执行
async function processArray(array) {
for (const item of array) {
await processItem(item); // 逐个处理
}
}
// 并行执行
async function processArray(array) {
const promises = array.map(item => processItem(item));
await Promise.all(promises); // 同时处理所有项
}
8. Promise 与 async/await 对比
| 特性 | Promise.then() | async/await |
|---|---|---|
| 语法 | 链式调用 | 同步风格 |
| 错误处理 | .catch() 方法 | try/catch 块 |
| 可读性 | 回调嵌套可能降低可读性 | 类似同步代码,更易理解 |
| 调试 | 调试困难 | 类似同步代码,易于调试 |
| 返回值 | 返回新的 Promise | 自动包装为 Promise |
| 流程控制 | 需要手动返回 Promise | 使用 await 暂停执行 |
9. 常见错误与解决方案
-
忘记 await:
// ❌ 错误:返回Promise而不是结果 async function getData() { const data = fetch('/api'); // 缺少await return data; } // ✅ 正确 async function getData() { const data = await fetch('/api'); return data; } -
忽略错误处理:
// ❌ 危险:未处理可能的错误 async function updateProfile() { await saveData(); } // ✅ 安全 async function updateProfile() { try { await saveData(); } catch (error) { handleError(error); } } -
不必要的顺序等待:
// ❌ 低效:顺序等待 async function loadResources() { const a = await getA(); // 等待A完成 const b = await getB(); // 再等待B完成 } // ✅ 高效:并行请求 async function loadResources() { const [a, b] = await Promise.all([getA(), getB()]); }
总结
JavaScript 的异步编程从回调函数发展到 Promise,再到现在的 async/await,提供了越来越强大的工具来处理异步操作:
- Promise:异步操作的容器
- .then():处理成功状态
- .catch():捕获错误
- .finally():执行清理操作
- async:声明异步函数
- await:暂停执行直到 Promise 完成
最佳实践:
- 优先使用 async/await 编写更清晰的异步代码
- 始终处理可能的错误(使用 try/catch 或 .catch())
- 并行操作使用 Promise.all() 提高性能
- 使用 .finally() 进行必要的资源清理
- 避免在循环中滥用顺序等待
掌握这些核心概念和模式,你将能够编写出高效、健壮且易于维护的 JavaScript 异步代码。