手撕算法(8)——promise的静态方法

62 阅读2分钟

Promise.all

Promise.all 方法接受一个 Promise 可迭代对象(例如数组),当所有 Promise 都 fulfilled 时返回一个新的 Promise,并将所有结果打包成数组传递给 resolve。如果有一个 Promise rejected,则直接返回该 rejected 的 Promise。

function myPromiseAll(promises) {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'));
        }

        if (promises.length === 0) {
            return resolve([]);
        }

        const results = [];
        let completedPromises = 0;

        promises.forEach((promise, index) => {
            Promise.resolve(promise).then(value => {
                results[index] = value;
                completedPromises += 1;

                if (completedPromises === promises.length) {
                    resolve(results);  // 所有的 promises 都已完成
                }
            }).catch(reject);  // 如果有一个 promise 失败,则直接 reject
        });
    });
}

Promise.any

Promise.any 方法接收一个可迭代对象,当其中的任意一个 Promise 成功时,返回该 Promise 的值;如果所有的 Promise 都失败,则返回一个拒绝状态的 Promise,并带有一个 AggregateError,该错误对象包含所有 Promise 的失败原因。

function myPromiseAny(promises) {
    return new Promise((resolve, reject) => {
        let errors = [];
        let rejectedPromises = 0;

        promises.forEach((promise) => {
            Promise.resolve(promise).then(resolve).catch(error => {
                errors.push(error);
                rejectedPromises++;
                if (rejectedPromises === promises.length) {
                    reject(new AggregateError(errors, 'All promises were rejected'));
                }
            });
        });
    });
}

Promise.race

Promise.race 方法接受一个 Promise 可迭代对象,但只要有一个 Promise 状态改变(无论是 fulfilled 还是 rejected),就会返回该 Promise 的结果。

function myPromiseRace(promises) {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'));
        }

        if (promises.length === 0) {
            return resolve([]);
        }

        promises.forEach(promise => {
            Promise.resolve(promise).then(resolve).catch(reject);
        });
    });
}

Promise.allSettled

Promise.allSettled 返回一个新的 Promise,该 Promise 在所有给定的 Promise 都已经 fulfilled 或 rejected 后完成,并返回一个对象数组,数组中每个对象表示对应的 Promise 结果,每个对象都有一个 status 属性,以及 value 或 reason 属性。

function myPromiseAllSettled(promises) {
    return new Promise((resolve) => {

        if (!Array.isArray(promises)) {
            return reject(new TypeError('Argument is not iterable'));
        }

        if (promises.length === 0) {
            return resolve([]);
        }

        let results = [];
        let completedPromises = 0;

        promises.forEach((promise, index) => {
            Promise.resolve(promise).then(value => {
                results[index] = { status: 'fulfilled', value: value };
                completedPromises++;
                if (completedPromises === promises.length) {
                    resolve(results);
                }
            }).catch(reason => {
                results[index] = { status: 'rejected', reason: reason };
                completedPromises++;
                if (completedPromises === promises.length) {
                    resolve(results);
                }
            });
        });
    });
}

用例

//测试 myPromiseAll
myPromiseAll([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]).then(console.log); // 输出: [1, 2, 3]

// 测试 myPromiseAny
myPromiseAny([
    Promise.reject('error1'),
    Promise.resolve('success'),
    Promise.reject('error2')
]).then(console.log).catch(console.error); // 输出: 'success'

// 测试 myPromiseRace
myPromiseRace([
    new Promise((resolve) => setTimeout(() => resolve('first'), 100)),
    new Promise((resolve) => setTimeout(() => resolve('second'), 200))
]).then(console.log); // 输出: 'first'

// 测试 myPromiseAllSettled
myPromiseAllSettled([
    Promise.resolve(1),
    Promise.reject('error'),
    Promise.resolve(3)
]).then(console.log); // 输出: [{status: "fulfilled", value: 1}, {status: "rejected", reason: "error"}, {status: "fulfilled", value: 3}]