前言
面试中让实现一个Promise.all方法,当时没有什么头绪,网上部分博客中的实现感觉也有些问题,所以参考他人的实现,然后加入一些自己的想法。
Promise.all的原理
Promise.all(iterable)
方法接收一个可迭代对象作为参数,比如Array
或String
,如果参数中所有的promise
都完成(resolved)或参数中不包含 promise
时回调完成(resolve);如果参数中 promise
有一个失败(rejected),此实例回调失败(reject),失败的原因是第一个失败 promise
的结果。
使用
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
要点
- 接收一个可迭代对象
iterable
作为参数 - 返回一个
Promise
对象 - 参数中所有的
promise
都完成(resolved)或参数中不包含promise
时回调完成(resolve) - 如果参数中
promise
有一个失败(rejected),此实例回调失败(reject)
实现代码
Promise.myAll = function(iterable) {
return new Promise((resolve, reject) => {
// 判断是否可迭代
if(typeof iterable[Symbol.iterator] !== "function") {
reject(`${iterable} is not iterable`);
}
let promisesLength = iterable.length;
// 长度为0时返回空数组
if(promisesLength === 0) {
resolve([]);
}
let resultArr = new Array(promisesLength);
let count = 0;
for(let [index, proItem] of Object.entries(iterable)) {
Promise.resolve(proItem).then(res => {
// 将结果放在对应位置
resultArr[index] = res;
count ++;
// 完成数量等于总数时,返回成功结果
if(count === promisesLength) {
resolve(resultArr);
}
}).catch(err => {
// 异常时立刻返回错误结果
reject(err);
})
}
})
}
测试
参数为字符串时,输出结果相同
参数为
Promise
数组,且全部resolved
参数为
Promise
数组,且有reject
拓展
依法炮制,实现一下其它几个Promise方法
allSettled
Promise.myAllSettled = function(iterable) {
return new Promise((resolve, reject) => {
if(typeof iterable[Symbol.iterator] !== "function") {
reject(`${iterable} is not iterable`);
}
let promisesLength = iterable.length;
if(promisesLength === 0) {
resolve([]);
}
let count = 0;
let resultArr = new Array(promisesLength);
for(let [index, proItem] of Object.entries(iterable)) {
Promise.resolve(proItem).then(res => {
resultArr[index] = {
status: "fulfilled",
value: res
}
}).catch(err => {
resultArr[index] = {
status: "rejected",
value: err
}
}).finally(() => {
count ++;
if(count === promisesLength) {
resolve(resultArr);
}
})
}
})
}
race
Promise.myRace = function(iterable) {
return new Promise((resolve, reject) => {
if(typeof iterable[Symbol.iterator] !== "function") {
reject(`${iterable} is not iterable`);
}
let promisesLength = iterable.length;
if(promisesLength === 0) {
resolve([]);
}
for(let proItem of iterable) {
Promise.resolve(proItem).then(res=> {
resolve(res);
}).catch(err => {
reject(err);
})
}
})
}
any
Promise.myAny = function(iterable) {
return new Promise((resolve, reject) => {
if(typeof iterable[Symbol.iterator] !== "function") {
reject(`${iterable} is not iterable`);
}
let promisesLength = iterable.length;
if(promisesLength === 0) {
reject(undefined);
}
let resultArr = new Array(promisesLength);
let count = 0;
for(let [index, proItem] of Object.entries(iterable)) {
Promise.resolve(proItem).then(res => {
resolve(res);
}).catch(err => {
resultArr[index] = err;
count ++;
if(count === promisesLength) {
reject(resultArr);
}
})
}
})
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!