手撕Promise之静态API

前言

Promise有六个常用的API,包括Promise.resolve()、Promise.reject()、Promise.all()、Promise.any()、Promise.allSelect()以及Promise.race()。前两个API很简单,这里我就过滤掉了,这篇博客主要是实现后面四个API,至于为什么会突然想到去实现这玩意,问就是因为大厂面试会让你现场手撕(裂开)。
这四个API实现的核心思路都差不多,所以我重点只讲述promise.all()的实现过程,后三个API我只给出最终代码。

Promise.all()

API功能

一个API的功能,我们重点关注其参数和返回值,下图是mdn上的介绍:
在这里插入图片描述
提取摘要:参数是个iterable,返回值是个promise。

思路分析

对于iterable,一般不太方便直接处理,所以我们可以使用Array.from将其转换为数组进行处理。然后判断数组是否为空,如果是空数组,直接返回Promise.resolve([])。否则返回一个需要进一步处理的promise,那么进入正题。
显然,我们肯定需要遍历数组并执行每一个promise,但是在外面我们还需要维护一个计数器,每fulfilled一个promise,计数器加1,如果计数器的值等于数组的长度,则将返回的promise执行resolve()。如果有任意一个promise被reject,那么将返回的promise执行reject()。

代码

实现代码:

function promiseAll(arr) {
    // 转换为数组
    const list = Array.from(arr);
    const n = list.length;
    // 特殊情形
    if (n === 0) {
        return Promise.resolve([]);
    }
    return new Promise((resolve, reject) => {
        const res = new Array(n);
        let count = 0;
        for (let i = 0; i < n; i++) {
            Promise.resolve(list[i]).then(r => {
                res[i] = r;
                count++;
                // 全部fulfilled
                if (count === n) {
                    resolve(res);
                }
            }).catch(e => {
                // 任意一个reject
                reject(e);
            });
        }
    })
}

测试代码:

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

promiseAll([promise1, promise2, promise3]).then((values) => {
  console.log(values);
});

promiseAll([])
promiseAll([1,2,Promise.resolve(3)])
promiseAll([Promise.resolve(2), 3, Promise.reject(4)]);

对于测试代码,大家可以直接对比原API进行比较。

Promise.any()

实现代码:

function promiseAny(arr) {
    const list = Array.from(arr);
    const n = list.length;
    if (n === 0) {
        return Promise.reject(new AggregateError([]));
    }
    return new Promise((resolve, reject) => {
        const res = new Array(n);
        let count = 0;
        for (let i = 0; i < n; i++) {
            Promise.resolve(list[i]).then(r => {
                resolve(r);
            }).catch(e => {
                res[i] = e;
                count++;
                if (count === n) {
                    reject(new AggregateError(res));
                }
            });
        }
    })
}

测试代码:

const pErr = new Promise((resolve, reject) => {
    reject("总是失败");
});

const pSlow = new Promise((resolve, reject) => {
    setTimeout(resolve, 500, "最终完成");
});

const pFast = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, "很快完成");
});

promiseAny([pErr, pSlow, pFast]).then((value) => {
    console.log(value);
})

Promise.allSelect()

实现代码:

function promiseAllSettled(arr) {
    const list = Array.from(arr);
    const n = list.length;
    if (n === 0) {
        return Promise.resolve([]);
    }
    return new Promise((resolve, reject) => {
        const res = new Array(n);
        let count = 0;
        for (let i = 0; i < n; i++) {
            Promise.resolve(list[i]).then(r => {
                res[i] = {
                    status: "fulfilled",
                    value: r
                };
                count++;
                if (count === n) {
                    resolve(res);
                }
            }).catch(e => {
                res[i] = {
                    status: "rejected",
                    reason: e
                };
                count++;
                if (count === n) {
                    resolve(res);
                }
            });
        }
    })
}

测试代码:

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

promiseAllSettled(promises).
    then((results) => results.forEach((result) => console.log(result)));

Promise.race()

实现代码:

function promiseRace(arr) {
    const list = Array.from(arr);
    const n = list.length;
    return new Promise((resolve, reject) => {
        // 如果n===0,则永远等待
        for (let i = 0; i < n; i++) {
            Promise.resolve(list[i]).then(r => {
                resolve(r);
            }).catch(e => {
                reject(e);
            });
        }
    })
}

测试代码:

const promise1 = new Promise((resolve, reject) => {
    setTimeout(resolve, 500, 'one');
});

const promise2 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'two');
});

promiseRace([promise1, promise2]).then((value) => {
    console.log(value);
});

结语

到此,本篇有关Promise静态API的讲述已临近尾声,不知大家是否感觉到重复造轮子也有几分乐趣。对于本篇文章的代码如果大家有疑问欢迎评论区留言,如果发现代码有bug也欢迎评论区指出。下期再会。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值