Promise.all (iterable): The all function returns a new promise which is fulfilled with an array of fulfillment values for the passed promises, or rejects with the reason of the first passed promise that rejects. It resolves all elements of the passed iterable to promises as it runs this algorithm.
Promise.all = Promise.all || function(promises) {
// 如果实参不是数组则报错返回
if (!isArray(promises)) {
throw new TypeError('You must pass an array to all.');
}
// 结果返回一个新的 Promise 实例
return new Promise(function(resolve, reject) {
var i = 0,
result = [],
len = promises.length,
count = len
// 使用闭包记录数组执行顺序
function resolver(index) {
return function(value) {
resolveAll(index, value);
};
}
// 只要有一个失败状态就变为 rejected
function rejecter(reason) {
reject(reason);
}
// 如果全部成功状态变为 resolved
function resolveAll(index, value) {
result[index] = value;
if (--count == 0) {
resolve(result)
}
}
// 遍历数组并发执行异步代码
for (; i < len; i++) {
promises[i].then(resolver(i), rejecter);
}
});
}
实现一个调度粒度可变的 Promise.all 静态方法
那么回到题目的问题:如何实现一个调度粒度可变的 Promise.all 静态方法呢?这里首先可能会产生一个疑问就是什么叫调度粒度可变,实际上很简单:就是给 all 方法增加一个正整数类型的参数,用来标识传入的 Promise 实例数组中可以并发执行的最大个数。
举例如下,声明三个不同异步时间的 Promise 实例并调用 all 方法,正常情况下(我们粗暴的认为)其执行时间应该为200ms(当然这是一个错误的答案,在这个例子当中我们仅考虑并发逻辑),而在调度粒度为1的 all 方法中其执行时间应该为450ms,在调度粒度为2的 all 方法中其执行时间应该为250ms,以此类推。
实现一个并发数可变的 Promise.all 静态方法
Promise.all 静态方法具有如下特性:
下面是 Promise.all 的简单用法:
如何实现 Promise.all 静态方法
实现一个调度粒度可变的 Promise.all 静态方法
举例如下,声明三个不同异步时间的 Promise 实例并调用 all 方法,正常情况下(我们粗暴的认为)其执行时间应该为200ms(当然这是一个错误的答案,在这个例子当中我们仅考虑并发逻辑),而在调度粒度为1的 all 方法中其执行时间应该为450ms,在调度粒度为2的 all 方法中其执行时间应该为250ms,以此类推。
在这种情况下,马上可以想到的一个方法是:我们可以使用队列的数据结构来实现调度粒度为1的 all 方法。
写到这儿不难发现,不同调度粒度实际上是对队列每次推出的 Promise 实例数量最大值的约束,以及对返回结果的顺序索引作出缓存,那么把代码进行简单的修改即可实现预期的功能。
为了能看出明显的区别我们把定时器的时间延长到秒,执行代码后完美验证。
至此结束。