深入理解 JavaScript Promise (承诺):现代异步编程的核心
在 JavaScript 的世界里,异步操作无处不在,无论是网络请求、文件读写、定时任务还是用户交互。传统的回调函数 (Callbacks) 虽然解决了 JavaScript 单线程的非阻塞问题,但随着异步逻辑的复杂化,很容易陷入臭名昭著的“回调地狱 (Callback Hell)”,导致代码难以阅读、维护和错误处理。
为了解决这一痛点,ES6 (ECMAScript 2015) 引入了 Promise (承诺)。Promise 是一种用于处理异步操作的机制,它代表了一个异步操作的最终完成(或失败)及其结果值。它提供了一种更结构化、更易于管理的方式来编写异步代码,极大地改善了可读性和可维护性,是现代 JavaScript 异步编程的基石。
本教程将深入探讨 Promise 的核心概念、其生命周期、如何创建和消费 Promise,以及如何利用 Promise 链式调用来处理复杂的异步序列。我们还将介绍 Promise 提供的高级 API,如 Promise.all() 和 Promise.race(),并简要提及 Promise 在解决“回调地狱”问题上的重要性,以及它为后续的 async/await 语法奠定的基础。
前置知识
在开始本教程之前,建议您具备以下 JavaScript 基础知识:
- 函数和作用域: 熟悉函数的定义、调用、参数传递以及闭包。
- 回调函数 (Callbacks): 对回调函数的工作原理及其在异步编程中的应用有基本了解,包括它们可能导致的“回调地狱”问题。
- JavaScript 事件循环 (Event Loop) (可选): 对 JavaScript 如何处理异步任务的机制有初步理解会更有帮助。
目录
- Promise (承诺) 简介
- 1.1 为什么需要 Promise?(从回调地狱说起)
- 1.2 什么是 Promise?
- 1.3 Promise 的核心思想
- Promise 的三种状态
- 2.1 Pending (待定)
- 2.2 Fulfilled / Resolved (已成功)
- 2.3 Rejected (已失败)
- 2.4 状态转换:不可逆性
- 创建 Promise
- 3.1
new Promise(executor)构造函数 - 3.2
resolve和reject函数的作用 - 3.3 异步操作与同步执行
- 3.1
- 消费 Promise:
.then(),.catch(),.finally()- 4.1
.then(onFulfilled, onRejected)方法 - 4.2
.catch(onRejected)方法 (错误处理) - 4.3
.finally(onFinally)方法 (最终处理)
- 4.1
- Promise 链式调用 (Chaining Promises)
- 5.1
.then()的返回值:一个新的 Promise - 5.2 返回值对后续
.then()的影响 (普通值 vs. Promise) - 5.3 构建顺序执行的异步操作流
- 5.1
- Promise 中的错误处理
- 6.1 错误冒泡机制
- 6.2
.catch()的重要性与放置位置 - 6.3 捕获未处理的 Promise 拒绝 (Uncaught Promise Rejections)
- Promise 的静态方法 (Promise Combinators)
- 7.1
Promise.all(iterable) - 7.2
Promise.race(iterable) - 7.3
Promise.any(iterable)(ES2021) - 7.4
Promise.allSettled(iterable)(ES2020) - 7.5
Promise.resolve(value) - 7.6
Promise.reject(reason)
- 7.1
- Promise 与
async/await的关系 (简要) - 最佳实践与注意事项
- 9.1 始终处理 Promise 的拒绝 (Rejection)
- 9.2 避免 Promise 构造函数中的同步错误
- 9.3 适当使用 Promise 静态方法
- 9.4 避免 Promise 嵌套过深 (即使用链式调用)
- 总结
- 附录:术语表
1. Promise (承诺) 简介
1.1 为什么需要 Promise?(从回调地狱说起)
在 Promise 出现之前,JavaScript 主要通过回调函数来处理异步操作。当我们需要执行一系列相互依赖的异步任务时,代码会很快变得层层嵌套,难以阅读、维护和错误处理,这种现象被称为“回调地狱 (Callback Hell)”或“厄运金字塔 (Pyramid of Doom)”。
回调地狱示例:
// 模拟异步操作
function fetchData(url, callback) {
setTimeout(() => {
// 假设成功获取数据
callback(null, { id: 1, url: url });
}, 1000);
}
function processData(data, callback) {
setTimeout(() => {
// 假设处理成功
callback(null, { processedId: data.id + 1 });
}, 800);
}
function displayResult(processedData, callback) {
setTimeout(() => {
console.log("最终结果:", processedData);
callback(null, "Display Done");
}, 500);
}
fetchData("api/user", (error, userData) => {
if (error) { console.error("Error fetching user:", error); return; }
processData(userData, (error, processedUserData) => {
if (error) { console.error("Error processing user:", error); return; }
displayResult(processedUserData, (error, result) => {
if (error) { console.error("Error displaying result:", error); return; }
console.log(result); // Display Done
});
});
});
这种代码风格不仅视觉上难以辨认,而且错误处理也变得很复杂。
1.2 什么是 Promise?
Promise 是一个代表了一个异步操作最终完成 (或失败) 的对象。它是一个占位符,代表着某个未来才会知道结果的值。当一个异步操作完成时,Promise 会发出通知,告知操作是成功了还是失败了,并携带相应的结果或错误信息。
你可以把 Promise 想象成一个“承诺”:
- 当你在商店预订了一件商品,商店给了你一张“提货单”——这就是一个 Promise。
- 这张提货单承诺你将来会得到商品(成功),或者退款(失败)。
- 在拿到提货单后,你可以去忙其他事情,不必一直守在商店。
- 当商品到货或无法供货时,商店会通知你(Promise 状态改变)。
1.3 Promise 的核心思想
- 分离关注点: 将异步操作的启动逻辑与其结果的处理逻辑分离开来。
- 链式调用: 允许将多个异步操作串联起来,形成一个清晰、线性的执行流程,解决了回调地狱的深层嵌套问题。
- 标准化错误处理: 提供统一的错误捕获机制,错误可以沿着 Promise 链传播,直到被处理。
2. Promise 的三种状态
一个 Promise 对象在其生命周期中,只会处于以下三种状态之一,并且状态只能从待定转换为已成功或已失败,一旦转换就不可逆转。
2.1 Pending (待定)
- 初始状态: 异步操作正在进行中,Promise 的结果尚未确定。
- 此时 Promise 既没有成功,也没有失败。
2.2 Fulfilled / Resolved (已成功)
- 操作成功: 异步操作成功完成。
- Promise 会带有一个成功值 (Value)。
- 状态从 Pending 变为 Fulfilled。
2.3 Rejected (已失败)
- 操作失败: 异步操作失败。
- Promise 会带有一个拒绝原因 (Reason / Error)。
- 状态从 Pending 变为 Rejected。
2.4 状态转换:不可逆性
一旦 Promise 状态从 Pending 变为 Fulfilled 或 Rejected,它的状态就不能再改变了,并且其结果值或拒绝原因也会永久确定。这意味着 Promise 只能成功一次或失败一次。
3. 创建 Promise
Promise 对象是通过 new Promise() 构造函数创建的。
3.1 new Promise(executor) 构造函数
Promise 构造函数接收一个名为 executor 的函数作为参数。这个 executor 函数会立即同步执行,并接收两个参数:resolve 和 reject,它们都是函数。
const myFirstPromise = new Promise((resolve, reject) => {
// executor 函数包含异步操作
// 它可以执行任何同步或异步代码
// 模拟一个异步操作,例如 2 秒后成功
setTimeout(() => {
const success = true; // 假设操作成功
if (success) {
resolve("操作成功了!"); // 调用 resolve,将 Promise 状态从 Pending 变为 Fulfilled
} else {
reject(new Error("操作失败了!")); // 调用 reject,将 Promise 状态从 Pending 变为 Rejected
}
}, 2000);
});
3.2 resolve 和 reject 函数的作用
resolve(value): 当异步操作成功时调用此函数。它将 Promise 的状态从Pending变为Fulfilled,并将value作为成功结果传递出去。reject(reason): 当异步操作失败时调用此函数。它将 Promise 的状态从Pending变为Rejected,并将reason(通常是一个Error对象) 作为失败原因传递出去。
3.3 异步操作与同步执行
executor 函数本身是同步执行的,但它内部通常会启动一个异步操作(例如 setTimeout, fetch, XMLHttpRequest 等)。异步操作完成后,再根据结果调用 resolve 或 reject。
console.log("1. 开始执行 Promise 前的代码");
const myPromise = new Promise((resolve, reject) => {
console.log("2. Promise executor 立即同步执行"); // 立即打印
setTimeout(() => {
console.log("4. 异步操作完成,调用 resolve"); // 2秒后打印
resolve("Data fetched!");
}, 2000);
});
console.log("3. Promise 构造后立即执行的代码"); // 立即打印
myPromise.then(result => {
console.log("5. Promise 成功处理:", result); // 2秒后打印
});
// 输出顺序:
// 1. 开始执行 Promise 前的代码
// 2. Promise executor 立即同步执行
// 3. Promise 构造后立即执行的代码
// (2秒后)
// 4. 异步操作完成,调用 resolve
// 5. Promise 成功处理: Data fetched!
4. 消费 Promise:.then(), .catch(), .finally()
一旦 Promise 被创建,我们就可以使用 .then(), .catch(), .finally() 方法来注册在 Promise 状态改变时要执行的回调函数。
4.1 .then(onFulfilled, onRejected) 方法
then() 方法是 Promise 最核心的消费方式。它返回一个新的 Promise,允许我们链式调用。
onFulfilled(函数,可选): 当 Promise 成功 (Fulfilled) 时调用。它接收 Promise 的成功值作为参数。onRejected(函数,可选): 当 Promise 失败 (Rejected) 时调用。它接收 Promise 的拒绝原因作为参数。
myFirstPromise.then(
(successValue) => {
console.log("Promise 成功了:", successValue); // 收到 "操作成功了!"
},
(failureReason) => {
console.error("Promise 失败了:", failureReason); // 收到 Error 对象
}
);
// 也可以只处理成功情况
myFirstPromise.then((value) => {
console.log("只处理成功:", value);
});
4.2 .catch(onRejected) 方法 (错误处理)
.catch(onRejected) 是 .then(null, onRejected) 的语法糖。它主要用于处理 Promise 链中的错误。当 Promise 失败时,它会执行 onRejected 回调函数。
const failedPromise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Something went wrong!")), 1000);
});
failedPromise.catch((error) => {
console.error("捕获到错误:", error.message); // 捕获到错误: Something went wrong!
});
强烈建议使用 .catch() 来处理 Promise 链中的错误,因为它能捕获到链中任何一个 Promise 的错误。
4.3 .finally(onFinally) 方法 (最终处理)
.finally() 方法(ES2018 引入)无论 Promise 成功还是失败,都会执行其回调函数。它不接收任何参数,并且不影响 Promise 的最终状态和结果。通常用于执行一些清理工作,如关闭加载动画。
const examplePromise = new Promise((resolve, reject) => {
// 模拟成功或失败
const random = Math.random();
setTimeout(() => {
if (random > 0.5) {
resolve("数据加载成功");
} else {
reject(new Error("数据加载失败"));
}
}, 1500);
});
examplePromise
.then((data) => {
console.log("成功处理:", data);
})
.catch((error) => {
console.error("错误处理:", error.message);
})
.finally(() => {
console.log("无论成功或失败,都会执行这个清理操作。");
// 例如:隐藏加载指示器
});
5. Promise 链式调用 (Chaining Promises)
Promise 最强大的特性之一是链式调用,它允许我们按顺序执行多个异步操作,避免了回调地狱。
5.1 .then() 的返回值:一个新的 Promise
每次调用 .then(), .catch(), .finally() 都会返回一个新的 Promise。这个新的 Promise 的状态和结果取决于上一个回调函数的返回值。
5.2 返回值对后续 .then() 的影响
-
如果回调函数返回一个普通值 (非 Promise):
- 这个值会被立即解析为一个成功 (Fulfilled) 的 Promise,并作为下一个
.then()的成功回调的参数。
Promise.resolve(1) .then(num => { console.log('第一步:', num); // 第一步: 1 return num * 2; // 返回普通值 }) .then(doubledNum => { console.log('第二步:', doubledNum); // 第二步: 2 return doubledNum + 3; }) .then(finalNum => { console.log('第三步:', finalNum); // 第三步: 5 }); - 这个值会被立即解析为一个成功 (Fulfilled) 的 Promise,并作为下一个
-
如果回调函数返回一个 Promise:
- 下一个
.then()会等待这个返回的 Promise 完成 (成功或失败),然后其结果 (成功值或拒绝原因) 将作为下一个.then()或.catch()的参数。这是实现异步链的关键。
function stepOne() { return new Promise(resolve => { setTimeout(() => { console.log('Step 1 complete'); resolve(10); }, 1000); }); } function stepTwo(value) { return new Promise(resolve => { setTimeout(() => { console.log(`Step 2 complete with value: ${value}`); resolve(value * 2); }, 1500); }); } function stepThree(value) { return new Promise(resolve => { setTimeout(() => { console.log(`Step 3 complete with value: ${value}`); resolve(value + 5); }, 800); }); } stepOne() .then(result1 => stepTwo(result1)) // 返回一个 Promise .then(result2 => stepThree(result2)) // 返回一个 Promise .then(finalResult => { console.log('All steps completed. Final result:', finalResult); // All steps completed. Final result: 25 }) .catch(error => { console.error('An error occurred:', error); }); - 下一个
5.3 构建顺序执行的异步操作流
通过链式调用,我们可以将多个异步操作组织成一个清晰的序列,每个操作都在前一个操作成功完成后才开始执行。
6. Promise 中的错误处理
Promise 链的错误处理机制非常强大和直观。
6.1 错误冒泡机制
- 当 Promise 链中的任何一个 Promise 被
rejected,或者任何一个onFulfilled或onRejected回调函数抛出同步错误,错误都会沿着 Promise 链向下冒泡,直到遇到第一个.catch()处理。 - 如果一个
.then()的onRejected回调成功处理了错误并返回了一个值(或 Promise),那么后续的.then()将会收到这个值,错误链被中断。
6.2 .catch() 的重要性与放置位置
- 单个
.catch()捕获链中所有错误: 通常将一个.catch()放在 Promise 链的末尾,可以捕获链中任何阶段发生的错误。 .then()中的onRejected: 虽然onRejected参数也可以捕获错误,但它只捕获其直接前面的 Promise 错误。如果onRejected自身抛出错误,则需要后续的.catch()来捕获。因此,通常推荐使用独立的.catch()来处理错误。
function riskyAsyncOperation(shouldFail) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldFail) {
reject(new Error("Operation failed!"));
} else {
resolve("Operation successful.");
}
}, 1000);
});
}
riskyAsyncOperation(false) // 成功路径
.then(data => {
console.log(data); // Operation successful.
return data.toUpperCase(); // 返回普通值
})
.then(processedData => {
console.log("Processed:", processedData); // Processed: OPERATION SUCCESSFUL.
// throw new Error("同步错误!"); // 可以在这里抛出同步错误
})
.catch(error => {
console.error("Caught in chain (success path):", error.message);
})
.finally(() => {
console.log("Finally block executed (success path).");
});
riskyAsyncOperation(true) // 失败路径
.then(data => {
console.log("This won't execute:", data);
})
.catch(error => { // 捕获到 "Operation failed!"
console.error("Caught in chain (failure path):", error.message);
// return "Error handled gracefully"; // 如果返回一个值,会解析为成功状态,后续 .then 会执行
})
.then(msg => { // 如果上面的 catch 返回了值,这个 then 会执行
console.log("After catch:", msg);
})
.finally(() => {
console.log("Finally block executed (failure path).");
});
6.3 捕获未处理的 Promise 拒绝 (Uncaught Promise Rejections)
如果一个 Promise 被拒绝,并且其拒绝没有在任何地方被 .catch() 处理,那么它将被视为一个未处理的 Promise 拒绝。在浏览器环境中,这通常会触发 unhandledrejection 事件;在 Node.js 中,这会导致进程崩溃。因此,始终处理 Promise 的拒绝是最佳实践。
7. Promise 的静态方法 (Promise Combinators)
Promise 对象提供了一些静态方法,用于处理多个 Promise 的并发执行和结果聚合。
7.1 Promise.all(iterable)
- 用途: 接收一个 Promise 可迭代对象(如数组),并返回一个新的 Promise。
- 行为: 只有当可迭代对象中的所有 Promise 都成功时,返回的 Promise 才会成功。它的成功值是一个数组,包含所有输入 Promise 的成功值,顺序与输入顺序一致。
- 失败: 只要有一个 Promise 失败,返回的 Promise 就会立即失败,其拒绝原因是最早失败的 Promise 的拒绝原因。
const p1 = Promise.resolve(3);
const p2 = 1337; // 普通值也会被 Promise.resolve() 包装
const p3 = new Promise((resolve, reject) => {
setTimeout(() => resolve("foo"), 100);
});
const p4 = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("oops")), 50); // 最早失败
});
Promise.all([p1, p2, p3])
.then(values => console.log('All success:', values)); // All success: [3, 1337, "foo"]
Promise.all([p1, p4, p3]) // p4 会导致 Promise.all 立即失败
.then(values => console.log(values))
.catch(error => console.error('All failed:', error.message)); // All failed: oops
7.2 Promise.race(iterable)
- 用途: 接收一个 Promise 可迭代对象,并返回一个新的 Promise。
- 行为: 一旦可迭代对象中的任何一个 Promise 率先完成(无论是成功还是失败),返回的 Promise 就会立即以那个 Promise 的结果(成功值或拒绝原因)完成。
- “竞赛”: 就像一场赛跑,谁先到达终点,谁就决定了最终的结果。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, 'two failed'); // 这个会先完成 (失败)
});
Promise.race([promise1, promise2])
.then(value => console.log('Race winner:', value))
.catch(error => console.error('Race loser:', error)); // Race loser: two failed
7.3 Promise.any(iterable) (ES2021)
- 用途: 接收一个 Promise 可迭代对象,并返回一个新的 Promise。
- 行为: 只有当可迭代对象中的任何一个 Promise 成功时,返回的 Promise 就会成功。它的成功值是第一个成功 Promise 的成功值。
- 失败: 只有当所有 Promise 都失败时,返回的 Promise 才会失败。它的拒绝原因是一个
AggregateError,包含了所有 Promise 的拒绝原因。
const pFail1 = new Promise((resolve, reject) => setTimeout(reject, 100, 'Error 1'));
const pFail2 = new Promise((resolve, reject) => setTimeout(reject, 200, 'Error 2'));
const pSuccess = new Promise((resolve, reject) => setTimeout(resolve, 150, 'Success!'));
Promise.any([pFail1, pSuccess, pFail2])
.then(value => console.log('Any winner:', value)) // Any winner: Success! (因为 pSuccess 先成功)
.catch(error => console.error(error));
const allFailed = [
new Promise((resolve, reject) => setTimeout(reject, 500, 'First Failure')),
new Promise((resolve, reject) => setTimeout(reject, 200, 'Second Failure')),
];
Promise.any(allFailed)
.then(value => console.log(value))
.catch(error => console.error('All failed with Any:', error.errors)); // AggregateError, 包含所有错误
7.4 Promise.allSettled(iterable) (ES2020)
- 用途: 接收一个 Promise 可迭代对象,并返回一个新的 Promise。
- 行为: 当所有输入 Promise 都已“settle”(无论成功还是失败)时,返回的 Promise 才会成功。它的成功值是一个对象数组,每个对象描述了相应 Promise 的状态和结果。
{ status: 'fulfilled', value: <成功值> }{ status: 'rejected', reason: <拒绝原因> }
- 特点: 不会因为某个 Promise 失败而短路,它总是等待所有 Promise 都完成。
const prom1 = Promise.resolve("Done!");
const prom2 = new Promise((resolve, reject) => setTimeout(() => reject("Oops!"), 100));
const prom3 = Promise.resolve(42);
Promise.allSettled([prom1, prom2, prom3])
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Promise ${index + 1} succeeded with value: ${result.value}`);
} else {
console.error(`Promise ${index + 1} failed with reason: ${result.reason}`);
}
});
});
// Output:
// Promise 1 succeeded with value: Done!
// Promise 2 failed with reason: Oops!
// Promise 3 succeeded with value: 42
7.5 Promise.resolve(value)
- 用途: 返回一个已经成功 (Fulfilled) 的 Promise,其成功值为
value。 - 如果
value本身是一个 Promise,则返回该 Promise。
const resolvedPromise = Promise.resolve("Hello");
resolvedPromise.then(val => console.log(val)); // Hello
const existingPromise = new Promise(res => res('Existing'));
Promise.resolve(existingPromise).then(val => console.log(val)); // Existing
7.6 Promise.reject(reason)
- 用途: 返回一个已经失败 (Rejected) 的 Promise,其拒绝原因为
reason。
const rejectedPromise = Promise.reject(new Error("Failed instantly"));
rejectedPromise.catch(err => console.error(err.message)); // Failed instantly
8. Promise 与 async/await 的关系 (简要)
async/await (ES2017 引入) 是基于 Promise 的语法糖。它允许你编写看起来像同步代码的异步代码,进一步提高了异步逻辑的可读性和可维护性,特别是在处理多个顺序异步操作时。
async函数总是返回一个 Promise。await关键字只能在async函数内部使用,它会暂停async函数的执行,直到其后面的 Promise 解决 (Fulfilled 或 Rejected)。如果 Promise 解决,await会返回 Promise 的成功值;如果 Promise 拒绝,await会抛出错误。
示例:
async function fetchUserAndOrders() {
try {
const user = await new Promise(res => setTimeout(() => res({ id: 1, name: "Bob" }), 1000));
console.log("Fetched user:", user);
const orders = await new Promise(res => setTimeout(() => res([{ id: 101, userId: user.id }]), 800));
console.log("Fetched orders:", orders);
return { user, orders };
} catch (error) {
console.error("Error in async function:", error);
throw error; // 重新抛出错误以便外部捕获
}
}
fetchUserAndOrders()
.then(data => console.log("Final data:", data))
.catch(err => console.error("Caught by .catch():", err));
虽然 async/await 带来了巨大的便利,但它并没有取代 Promise,而是建立在 Promise 之上,使其更易于使用。
9. 最佳实践与注意事项
9.1 始终处理 Promise 的拒绝 (Rejection)
一个未处理的 Promise 拒绝是应用程序中的潜在错误源。在 Promise 链的末尾添加 .catch(),或者在 async 函数中使用 try...catch 块,确保所有错误都被妥善处理。
9.2 避免 Promise 构造函数中的同步错误
executor 函数中的同步错误会被自动捕获并导致 Promise 拒绝。但如果错误发生在 resolve 或 reject 调用之后,则不会被 Promise 捕获。尽量将所有逻辑放在 Promise 内部的异步操作中,或确保所有潜在的同步错误都被 try...catch 包裹。
9.3 适当使用 Promise 静态方法
根据您的需求选择正确的 Promise 组合器:
Promise.all适用于所有并发操作都必须成功的情况。Promise.race适用于只需要最快结果的情况。Promise.any适用于只需要第一个成功结果的情况。Promise.allSettled适用于需要等待所有操作完成,并获取它们各自结果(无论成功失败)的情况。
9.4 避免 Promise 嵌套过深 (即使用链式调用)
即使是 Promise 也可以被滥用导致嵌套。始终尝试返回 Promise 并使用 .then() 链式调用,而不是在 .then() 内部嵌套另一个 Promise。
不推荐:
somePromise().then(result1 => {
anotherPromise(result1).then(result2 => {
thirdPromise(result2).then(finalResult => {
// ...
});
});
});
推荐:
somePromise()
.then(result1 => anotherPromise(result1))
.then(result2 => thirdPromise(result2))
.then(finalResult => {
// ...
})
.catch(error => {
// ...
});
10. 总结
Promise 彻底改变了 JavaScript 异步编程的面貌,它从根本上解决了传统回调函数的深层嵌套和错误处理难题。通过将异步操作包装成一个具有明确状态 (Pending, Fulfilled, Rejected) 的对象,Promise 提供了:
- 清晰的异步流程控制: 通过
.then()链式调用,将复杂的异步序列转化为可读性强的线性代码。 - 统一的错误处理机制:
.catch()方法能够捕获链中任何环节的错误,避免了冗余的错误检查。 - 强大的组合能力:
Promise.all(),Promise.race(),Promise.any(),Promise.allSettled()等静态方法,使得并行和竞争的异步任务管理变得简单高效。
理解和熟练运用 Promise 是现代 JavaScript 开发者的必备技能。它不仅自身非常强大,更是 async/await 语法的基础,为构建高性能、可维护的 Web 应用程序奠定了坚实的基础。
11. 附录:术语表
- Promise (承诺): 代表一个异步操作的最终完成(或失败)及其结果值的对象。
- Pending (待定): Promise 的初始状态,表示异步操作仍在进行中。
- Fulfilled / Resolved (已成功): Promise 的状态,表示异步操作成功完成,并带有一个成功值。
- Rejected (已失败): Promise 的状态,表示异步操作失败,并带有一个拒绝原因。
executor函数:new Promise()构造函数接收的函数,它包含异步操作逻辑,并接收resolve和reject作为参数。resolve(value):executor函数中用于将 Promise 状态设置为Fulfilled并传递成功值的函数。reject(reason):executor函数中用于将 Promise 状态设置为Rejected并传递拒绝原因的函数。.then(onFulfilled, onRejected): 消费 Promise 的方法,用于注册成功和失败时的回调函数,并返回一个新的 Promise。.catch(onRejected):.then(null, onRejected)的语法糖,主要用于处理 Promise 链中的错误。.finally(onFinally): 无论 Promise 成功或失败都会执行的回调方法,不影响最终状态和结果。- Promise 链 (Promise Chain): 通过连续调用
.then()方法将多个异步操作串联起来的结构。 - 回调地狱 (Callback Hell): 指深层嵌套的回调函数导致代码难以阅读、维护和调试的问题。
Promise.all(): 等待所有 Promise 都成功后才成功的 Promise 组合器。Promise.race(): 只要其中一个 Promise 率先完成(成功或失败)就完成的 Promise 组合器。Promise.any(): 只要其中一个 Promise 成功就成功的 Promise 组合器,所有失败才会失败。Promise.allSettled(): 等待所有 Promise 都完成(无论成功失败)后才成功的 Promise 组合器,返回所有结果的数组。Promise.resolve(value): 返回一个已成功的 Promise。Promise.reject(reason): 返回一个已失败的 Promise。async/await: 基于 Promise 的语法糖,用于编写更易读的异步代码。unhandledrejection事件: 当 Promise 被拒绝且没有被任何.catch()处理时,浏览器会触发的事件。
更多推荐



所有评论(0)