理解 Promise 的三种状态(Pending, Fulfilled, Rejected)及其生命周期。
掌握 Promise 的核心语法,包括 new Promise、.then()、.catch() 和 .finally()。
熟练运用高级组合方法(all, allSettled, race, any)处理复杂的并发异步任务。
学会利用 Promise 解决“回调地狱”问题,并实现超时控制和串行 / 并行混合执行模式。
JavaScript Promise 是处理异步操作(如 API 调用、文件加载、定时延迟)的现代标准。你可以将 Promise 想象成一个未来值的占位符。它代表一个现在可能未完成,但将来一定会完成(或失败)的操作。
Promise 对象在其生命周期中处于以下三种状态之一:
Pending (待定): 初始状态,操作尚未完成,既未成功也未失败。
Fulfilled (已兑现): 操作成功完成,Promise 拥有一个确定的结果值。
Rejected (已拒绝): 操作失败,Promise 拥有一个表示错误原因的变量。
注意: 状态一旦从 Pending 变为 Fulfilled 或 Rejected,就不可再改变(不可逆)。
判断奇偶数
// 创建一个 Promise
let checkEven = new Promise((resolve, reject) => {
let number = 4;
// 模拟逻辑判断
if (number % 2 === 0) {
resolve("这个数字是偶数!"); // 成功
} else {
reject("这个数字是奇数!"); // 失败
}
});
// 处理结果
checkEven
.then((message) => console.log(message)) // 成功时执行
.catch((error) => console.error(error)); // 失败时执行关键点说明:
resolve 和 reject 只是参数名,并非 JavaScript 关键字。你可以将它们命名为 success 和 failure,但为了代码可读性,建议遵循社区惯例使用 resolve 和 reject。
.then() 接收成功后的回调函数。
.catch() 接收失败后的回调函数。
let promise = new Promise((resolve, reject) => {
// 执行异步操作 (例如:网络请求、定时器)
if (/* 操作成功 */) {
resolve("任务成功完成");
} else {
reject("任务失败,发生错误");
}
});resolve(value): 将 Promise 状态标记为 Fulfilled,并传递结果值。
reject(error): 将 Promise 状态标记为 Rejected,并传递错误对象或信息。
为了更高效地处理复杂的异步场景,JavaScript 提供了一系列强大的静态方法和模式。
Promise.all()
等待所有 Promise 成功完成。如果其中任何一个失败,整个 Promise.all 会立即拒绝。
适用场景: 需要同时获取多个数据,且所有数据都必须成功才能继续后续逻辑(如加载页面的多个核心组件)。
Promise.all([
Promise.resolve("任务 1 完成"),
Promise.resolve("任务 2 完成"),
Promise.reject("任务 3 失败") // 只要有一个失败,整体即失败
])
.then((results) => console.log("所有结果:", results))
.catch((error) => console.error("发生错误:", error));
// 输出: 发生错误:任务 3 失败Promise.allSettled()
等待所有 Promise 结束(无论成功或失败),返回一个包含每个 Promise 结果的数组。
适用场景: 需要知道每个任务的状态,即使部分失败也要处理其他成功的结果(如批量上传文件,统计成功和失败的数量)。
Promise.allSettled([
Promise.resolve("任务 1 完成"),
Promise.reject("任务 2 失败"),
Promise.resolve("任务 3 完成")
])
.then((results) => console.log(results));
/* 输出示例:
[
{ status: 'fulfilled', value: '任务 1 完成' },
{ status: 'rejected', reason: '任务 2 失败' },
{ status: 'fulfilled', value: '任务 3 完成' }
]
*/Promise.race()
返回第一个settled(成功或失败)的 Promise 的结果。一旦有一个完成,其他的将被忽略。
适用场景: 多个备用源获取数据,谁快用谁;或者实现超时机制。
Promise.race([
new Promise((resolve) =>
setTimeout(() => resolve("任务 1 完成"), 1000)),
new Promise((resolve) =>
setTimeout(() => resolve("任务 2 完成"), 500)) // 这个更快
])
.then((result) => console.log(result));
// 输出: 任务 2 完成Promise.any()
返回第一个成功的 Promise。只有当所有 Promise 都失败时,它才会拒绝,并抛出一个 AggregateError。
适用场景: 尝试多个镜像服务器下载资源,只要有一个成功即可。
Promise.any([
Promise.reject("任务 1 失败"),
Promise.resolve("任务 2 成功"), // 第一个成功的
Promise.resolve("任务 3 成功")
])
.then((result) => console.log(result))
.catch((error) => console.error(error));
// 输出: 任务 2 成功Promise.resolve(value): 直接返回一个已成功的 Promise。常用于将非 Promise 值标准化为 Promise。
Promise.reject(reason): 直接返回一个已失败的 Promise。
Promise.resolve("立即成功")
.then((value) => console.log(value));
Promise.reject("立即失败")
.catch((error) => console.error(error));Promise.finally()
无论 Promise 成功还是失败,都会执行的代码块。常用于清理工作(如隐藏 Loading 动画、关闭数据库连接)。
Promise.resolve("任务完成")
.then((result) => console.log(result))
.catch((error) => console.error(error))
.finally(() => console.log("清理工作已完成"));
// 输出顺序: 任务完成 -> 清理工作已完成通过 .then() 方法串联多个异步操作,前一个 .then() 的返回值会自动传递给下一个 .then()。
Promise.resolve(5)
.then((value) => value * 2) // 返回 10
.then((value) => value + 3) // 返回 13
.then((finalValue) => console.log(finalValue));
// 输出: 13如果需要按顺序执行一系列异步任务(后一个依赖前一个的结果),可以使用 Array.prototype.reduce()。
let tasks = [1, 2, 3];
tasks.reduce((prevPromise, current) => {
return prevPromise.then(() => {
return new Promise((resolve) => {
console.log(`正在处理任务 ${current}`);
setTimeout(resolve, 500); // 模拟异步耗时
});
});
}, Promise.resolve()); // 初始值为一个已解决的 Promise
// 输出顺序: 任务 1 -> 任务 2 -> 任务 3 (每隔 0.5 秒)根据运行时条件动态创建和解决 Promise。
function asyncTask(taskName) {
return new Promise((resolve) => {
setTimeout(() =>
resolve(`${taskName} 已完成`), 1000);
});
}
asyncTask("下载文件").then((result) =>
console.log(result));结合 Promise.race() 实现异步操作的超时中断。
// 模拟一个耗时 3 秒的数据获取
let fetchData = new Promise((resolve) =>
setTimeout(() => resolve("数据加载成功"), 3000));
// 创建一个 2 秒后拒绝的超时 Promise
let timeout = new Promise((_, reject) =>
setTimeout(() => reject("请求超时!"), 2000));
// 竞赛:谁先完成就用谁的结果
Promise.race([fetchData, timeout])
.then((result) => console.log(result))
.catch((error) => console.error(error));
// 输出: 请求超时! (因为 2s < 3s)先并行执行一组任务,待它们全部完成后,再串行执行后续任务。
Promise.all([
new Promise((resolve) =>
setTimeout(() => resolve("任务 A 完成"), 1000)),
new Promise((resolve) =>
setTimeout(() => resolve("任务 B 完成"), 500))
])
.then(([resultA, resultB]) => {
console.log("并行结果:", resultA, resultB);
// 并行结束后,开始新的串行任务
return new Promise((resolve) =>
setTimeout(() => resolve("最终任务完成"), 700));
})
.then((finalResult) =>
console.log(finalResult));将传统的基于回调的函数转换为基于 Promise 的函数,以便使用 .then() 链或 await。
// 传统回调风格函数
function loadData(callback) {
setTimeout(() => callback("数据已加载"), 1000);
}
// 封装为 Promise
function promisifiedLoadData() {
return new Promise((resolve) => {
loadData((result) => resolve(result));
});
}
// 使用 Promise 风格调用
promisifiedLoadData().then((data) =>
console.log(data));避免回调地狱: Promise 将嵌套的回调转化为线性的链式调用,极大提升了代码可读性。
统一错误处理: 错误可以在链条末尾一次性捕获,简化了异常管理逻辑。
灵活的组合能力: 通过 all, race 等方法,可以优雅地处理复杂的并发和竞争场景。
状态机: 理解 Promise 的三种状态及其不可逆性是基础。
链式调用: 利用 .then() 传递数据,利用 .catch() 统一捕获错误。
组合方法:
需全部成功:用 Promise.all。
需全部结果(不管成败):用 Promise.allSettled。
需最快结果:用 Promise.race。
需首个成功:用 Promise.any。
实用模式: 掌握超时控制和回调转 Promise 的技巧,能解决大量实际工程问题。