自己实现简易版promise的all、race、allSettled和any

补充知识:

  • promise一共有三个状态:pending、rejected、fulfilled
  • 只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
  • 一旦状态改变,就不会再变,Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected

一、promise.all

特点:

  • 参数是可迭代对象(Iterator),里边的每一项都是promise实例(如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理)
  • 返回值是个promise实例
  • 如果全部成功,状态变为resolved, 并且返回值组成一个数组传给回调
  • 但凡有一个失败,状态变为rejected, 并将error返回给回调
  • 返回结果严格按照传入的promise顺序返回

代码:

function all(iterable) {
    return new Promise((resolve, reject) => {
        let result = []; // 存放结果
        let count = 0;   //记录有几个resolve
        // 空
        if (!iterable || iterable.length === 0) {
            resolve([]);
            return;
        }

        for (let i = 0; i < iterable.length; i++) {
            let promise = iterable[i];
            // 如果不是promise实例,就转成promise
            if (!(promise instanceof Promise)) {
                promise = Promise.resolve(promise);
            }
            promise.then(
                (value) => {
                    result[i] = value;
                    count++;
                    if (count === iterable.length) {
                        resolve(result);
                    }
                }
            ).catch(
                (err) => {
                    reject(err);
                }
            );
        }
    });
}

验证:

// 有一个reject验证
let p1 = Promise.resolve(1),
    p2 = Promise.reject(2),
    p3 = Promise.resolve(3);

all([p1,p2,p3]).then((res) => {
    console.log(res, 'res');
}).catch((err) => {
    console.log(err, 'err')
});

// 2 err
// 所有都resolve验证
let p1 = Promise.resolve(1),
    p2 = Promise.resolve(2),
    p3 = Promise.resolve(3);

all([p1,p2,p3]).then((res) => {
    console.log(res, 'res');
}).catch((err) => {
    console.log(err, 'err')
});

// [ 1, 2, 3 ] res
// 有非promise验证
let p1 = Promise.resolve(1),
    p2 = Promise.resolve(2),
    p3 = Promise.resolve(3);

all([0,p1,p2,p3]).then((res) => {
    console.log(res, 'res');
}).catch((err) => {
    console.log(err, 'err')
});

// [ 0, 1, 2, 3 ] res

二、promise.race

race是比赛、竞赛的意思,所以顾名思义,就是看谁快,就返回谁。

特点:

  • 参数是可迭代对象(Iterator),里边的每一项都是promise实例(如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理)
  • 返回值是个promise实例
  • 有一个实例改变状态(不管是resolve还是reject),就结束,并将该实例的结果返回给回调函数

代码:

function race(iterable) {
    return new Promise((resolve, reject) => {
        // 空
        if (!iterable || iterable.length === 0) {
            resolve([]);
            return;
        }

        for (let i = 0; i < iterable.length; i++) {
            let promise = iterable[i];
            // 如果不是promise实例,就转成promise
            if (!(promise instanceof Promise)) {
                promise = Promise.resolve(promise);
            }
            promise.then(
                (value) => {
                    resolve(value);
                }
            ).catch(
                (err) => {
                    reject(err);
                }
            );
        }
    });
}

验证:

// 都成功验证
let p1 = Promise.resolve(1),
    p2 = Promise.resolve(2),
    p3 = Promise.resolve(3);
    
race([p1,p2,p3]).then((res) => {
    console.log(res, 'res');
}).catch((err) => {
    console.log(err, 'err')
});

// 1 res
// 有失败的验证
let p1 = Promise.reject(1),
    p2 = Promise.reject(2),
    p3 = Promise.resolve(3);
    
race([p1,p2,p3]).then((res) => {
    console.log(res, 'res');
}).catch((err) => {
    console.log(err, 'err')
});

// 1 res

 

三、promise.allSettled

特点:

  • 参数是可迭代对象(Iterator),里边的每一项都是promise实例(如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理)
  • 返回值是个promise实例
  • 只有所有结果都返回才结束(不管是resolve还是reject),以数组形式返回所有结果,每一个结果是一个对象,包含value和status,ES2020引入
[{ status: "rejected", reason: error1 }, { status: "fulfilled", value: 1 }];

代码:

// 按照规定格式处理返回结果
const formatSettledResult = (success, value) =>
  success
    ? { status: "fulfilled", value }
    : { status: "rejected", reason: value };

function allSettled(iterable) {
    return new Promise((resolve, reject) => {
        let len = iterable.length;
        // 空
        if (!iterable || len === 0) {
            resolve([]);
            return;
        }
        let result = []; // 保存已结束的结果 
        for (let i = 0; i < len; i++) {
            let promise = iterable[i];
            // 如果不是promise实例,就转成promise
            if (!(promise instanceof Promise)) {
                promise = Promise.resolve(promise);
            }
            promise.then(
                (value) => {
                    result[i] = formatSettledResult(true, value);
                    if (result.length === len) {
                        resolve(result);
                    }
                }
            ).catch(
                (err) => {
                    result[i] = formatSettledResult(false, err);
                    if (result.length === len) {
                        resolve(result);
                    }
                }
            );
        }
    });
}

 验证:

// 验证
let p1 = Promise.reject(1),
    p2 = Promise.reject(2),
    p3 = Promise.resolve(3);
    
allSettled([p1,p2,p3]).then((res) => {
    console.log(res, 'res');
}).catch((err) => {
    console.log(err, 'err')
});

/*[
  { status: 'rejected', reason: 1 },
  { status: 'rejected', reason: 2 },
  { status: 'fulfilled', value: 3 }
] res
*/

四、promise.any

与promise.all正好相反

特点:

  • 参数是可迭代对象(Iterator),里边的每一项都是promise实例(如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理)
  • 返回值是个promise实例
  • 只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态,并将结果以数组形式返回
  • 不会因为某个 Promise 变成rejected状态而结束

代码:

function any(iterable) {
    return new Promise((resolve, reject) => {
        let len = iterable.length;
        // 空
        if (!iterable || len === 0) {
            resolve([]);
            return;
        }
        let result = []; // 保存rejected的结果 
        for (let i = 0; i < len; i++) {
            let promise = iterable[i];
            // 如果不是promise实例,就转成promise
            if (!(promise instanceof Promise)) {
                promise = Promise.resolve(promise);
            }
            promise.then(
                (value) => {
                    resolve(value);
                }
            ).catch(
                (err) => {
                    result[i] = err;
                    if (result.length === len) {
                        reject(result);
                    }
                }
            );
        }
    });
}

验证:

// 验证
let p1 = Promise.reject(1),
    p2 = Promise.reject(2),
    p3 = Promise.reject(3);
    
any([p1,p2,p3]).then((res) => {
    console.log(res, 'res');
}).catch((err) => {
    console.log(err, 'err')
});

// [ 1, 2, 3 ] err
// 验证
let p1 = Promise.reject(1),
    p2 = Promise.reject(2),
    p3 = Promise.resolve(3);
    
any([p1,p2,p3]).then((res) => {
    console.log(res, 'res');
}).catch((err) => {
    console.log(err, 'err')
});

// 3 res

总结:以上就是所有内容,是不是觉得一点都不难!! 只要了解每个API的特点,就能很轻松的实现了,不过我这只是简易版,容错性比较差,仅供参考。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值