前言
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也欢迎评论区指出。下期再会。
|