promise

Promise 是 JavaScript 异步编程的核心解决方案,它代表了一个异步操作的最终完成(或失败)及其结果值。

1. Promise 的核心概念与状态

1.1 三种状态 (States)

一个 Promise 必然处于以下三种状态之一,且状态的改变是不可逆的。

  1. Pending (待定): 初始状态。既没有被兑现(fulfilled),也没有被拒绝(rejected)。
  2. Fulfilled (已兑现/已成功): 意味着操作成功完成。此时会有一个 result (值)。
  3. Rejected (已拒绝/已失败): 意味着操作失败。此时会有一个 error (通常是一个 Error 对象)。

1.2 状态转化 (State Transitions)

Promise 的状态流转只有两个方向,一旦发生,状态就固定 (Settled) 了,不会再变:

  • Pending -> Fulfilled: 调用 resolve(value)
  • Pending -> Rejected: 调用 reject(reason) 或执行器函数内抛出异常。

1.3 基本语法

js
123456789101112
const myPromise = new Promise((resolve, reject) => {
    // 这是一个 "Executor" (执行器) 函数,会立即执行
    const success = true;

    if (success) {
        // 将状态从 Pending 改为 Fulfilled
        resolve("操作成功!"); 
    } else {
        // 将状态从 Pending 改为 Rejected
        reject(new Error("操作失败...")); 
    }
});

2. 实例方法 (Instance Methods)

创建 Promise 后,我们通过以下方法处理结果:

2.1 .then(onFulfilled, onRejected)

  • 接收两个函数作为参数。
  • 第一个参数在 Promise 成功时执行。
  • 第二个参数在 Promise 失败时执行(可选,一般常用 .catch 代替)。
  • 链式调用: .then 返回一个新的 Promise。

2.2 .catch(onRejected)

  • 专门用于捕获错误(Rejected 状态)。
  • 等同于 .then(null, onRejected)。
  • 具有“冒泡”性质,可以捕获前面链中任何一个步骤抛出的错误。

2.3 .finally(onFinally)

  • 无论 Promise 是成功还是失败,都会执行。
  • 通常用于清理工作(如关闭加载动画、关闭数据库连接)。

3. 静态方法 (Static Methods) - 并发与调度

这是你提到的类似于 Promise.all 的方法集合。它们用于处理多个 Promise 的组合情况。

3.1 Promise.all([p1, p2, ...]) (全有或全无)

  • 机制: 接收一个 Promise 数组(或可迭代对象)。
  • 成功: 只有当所有 Promise 都成功时,才返回成功,结果是结果数组。
  • 失败: 只要有任意一个 Promise 失败,立即返回失败(短路效应),错误信息是那个失败的 Promise 的错误信息。
js
123456789
const p1 = Promise.resolve(3);
const p2 = 42;
const p3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([p1, p2, p3]).then((values) => {
  console.log(values); // [3, 42, "foo"]
});

3.2 Promise.allSettled([p1, p2, ...]) (无论死活,都要结果)

  • 机制: 等待所有 Promise 完成,无论它们是成功还是失败。
  • 结果: 返回一个对象数组,每个对象包含 status ('fulfilled' 或 'rejected') 和对应的 value 或 reason。
  • 适用场景: 并发请求,不关心其中某些是否失败,想拿到所有结果时。
js
12345678910
const p1 = Promise.resolve('Success');
const p2 = Promise.reject('Fail');

Promise.allSettled([p1, p2]).then((results) => {
  // results: 
  // [
  //   { status: 'fulfilled', value: 'Success' },
  //   { status: 'rejected', reason: 'Fail' }
  // ]
});

3.3 Promise.race([p1, p2, ...]) (赛跑,谁快谁赢)

  • 机制: 哪个 Promise 最先解决(无论是成功还是失败),Promise.race 就返回那个结果。
  • 适用场景: 设置请求超时(网络请求 vs 设定时间的 Reject)。
js
123456
const pSlow = new Promise(resolve => setTimeout(resolve, 500, '慢'));
const pFast = new Promise(resolve => setTimeout(resolve, 100, '快'));

Promise.race([pSlow, pFast]).then((value) => {
  console.log(value); // "快"
});

3.4 Promise.any([p1, p2, ...]) (求生欲,只要一个成功)

  • 机制: 等待直到有任意一个 Promise 成功。
  • 成功: 返回第一个成功的 Promise 的值。
  • 失败: 只有当所有 Promise 都失败时,才返回失败(AggregateError)。
  • 区别: 与 race 不同,any 会忽略失败的 Promise,直到遇到成功的。
js
1234567
const pErr = Promise.reject('错误');
const pSlow = new Promise(resolve => setTimeout(resolve, 500, '慢但成功'));
const pFast = new Promise(resolve => setTimeout(resolve, 100, '快但成功'));

Promise.any([pErr, pSlow, pFast]).then((value) => {
  console.log(value); // "快但成功" (忽略了 pErr)
});

3.5 辅助方法

  • Promise.resolve(value): 快速创建一个状态为 Fulfilled 的 Promise。
  • Promise.reject(reason): 快速创建一个状态为 Rejected 的 Promise。

4. 总结对比表

方法描述成功条件失败条件
Promise.all并行执行,且必须全部成功所有都成功任意一个失败 (立即返回)
Promise.allSettled并行执行,获取所有结果总是成功 (等待所有完成)不会失败 (除非迭代器本身出错)
Promise.race赛跑,以最快的为准第一个 Settled 的是成功第一个 Settled 的是失败
Promise.any只要有一个成功即可任意一个成功所有都失败

5. 最佳实践代码示例

js
12345678910111213141516171819202122232425262728293031323334353637
// 模拟两个异步任务
const fetchUser = () => new Promise(resolve => setTimeout(() => resolve("用户数据"), 1000));
const fetchPosts = () => new Promise(resolve => setTimeout(() => resolve("文章数据"), 1500));
const fetchError = () => new Promise((_, reject) => setTimeout(() => reject("连接超时"), 500));

async function main() {
    console.log("--- 开始 Promise.all 演示 ---");
    try {
        // 只有两个都成功才会打印
        const [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);
        console.log(`Promise.all 结果: ${user}, ${posts}`);
    } catch (e) {
        console.error("Promise.all 出错:", e);
    }

    console.log("\n--- 开始 Promise.allSettled 演示 ---");
    // 即使包含 fetchError,也会返回所有结果
    const results = await Promise.allSettled([fetchUser(), fetchError()]);
    results.forEach((res, index) => {
        if (res.status === 'fulfilled') {
            console.log(`任务 ${index} 成功: ${res.value}`);
        } else {
            console.log(`任务 ${index} 失败: ${res.reason}`);
        }
    });
    
    console.log("\n--- 开始 Promise.any 演示 ---");
    try {
        // 忽略 fetchError,返回最快成功的 fetchUser
        const firstSuccess = await Promise.any([fetchError(), fetchUser(), fetchPosts()]);
        console.log(`Promise.any 赢家: ${firstSuccess}`);
    } catch (e) {
        console.log("全军覆没");
    }
}

main();