手写Promise.all
原生Promise方法概述
Promise原生的all方法的参数接收一个数组,该数组包含若干promise对象。当所有的promise都resolve时,all方法才会resolve;但凡有一个失败了,all方法就会reject。
手写Promise.all的思路
-
首先我们得先判断传入的参数是否是可迭代对象,如数组、Set集合(本次示例均使用数组展示);如果不是就return;
-
如果传入的是一个空数组,也return;
-
其次需要知道传入的数组中是否都是promise对象,如果不是就将其转换为promise对象;
-
那么经过层层筛选,数组中各项已经全部成为Promise对象了;使用变量
settledCount记录已经进入已决阶段的Promise(不管Promise是被resolve还是被reject),另外使用变量results记录进入Promise; -
使用
for...in循环对每一个promise进行加工,每循环到一个promise就可以调用then方法将该promise设置成resolve或者reject状态,每一个promise都会进入finally并且让settledCount++,判断settledCount === results.length,如果相等就可以返回resolve了 注意: -
一定要使用for..of..循环或者for..in..循环,不要使用for循环,因为传入的可迭代对象不一定是数组,for循环中需要用到元素下标,像set集合、map集合等都没有元素下标,因此for循环不适用
-
如果传入的可迭代对象不是promise就要将其转换成promise
-
不要使用数组的push方法,因为每一个promise成为已决状态的时间点不确定,因此使用for..in..或者for..of..循环可以让每个promise成为已决后回到自身应处的位置
Promise.myAll = function (iterable) {
//判断iterable迭代对象是否除了Promise以外还有其他参数(例如数字、字符串等)不是Promise对象,就需要使用Promise.resolve(xxx)变成Promise对象
//使用es6的扩展运算符可以判断iterable是否是可迭代对象
const promiseArr = [...iterable].map((item) =>
item instanceof Promise ? item : Promise.resolve(item)
);
//如果promiseArr数组长度为零就resolve()掉
if (promiseArr.length === 0) return Promise.resolve([]);
//该方法会返回一个Promise对象
return new Promise((resolve, reject) => {
//用于接收resolve的promise
let results = [];
//用于接收已经处于已决阶段的promise
let settledCount = 0;
for (let p in promiseArr) {
promiseArr[p]
.then((res) => {
//该项promise就设置成resolve状态
results[p] = res;
}, reject)
.finally(() => {
//不管promise被resolve了还是被reject了,settledCount都会++
settledCount++;
//直至已经进入已决阶段的promise的数量等于了处于resolve状态的promise就resolve
if (settledCount === results.length) {
resolve(results);
}
});
}
});
};