手写 Promise.all
Promise.all 的使用方法
-
语法
Promise.all(iterable);
-
参数
iterable
一个可迭代对象,如 Array 或 String。 -
返回值
- 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise。
- 如果传入的参数不包含任何 promise,则返回一个异步完成(asynchronously resolved)Promise。
- 其它情况下返回一个处理中(pending)的Promise。这个返回的 promise 之后会在所有的 promise 都完成或有一个 promise 失败时异步地变为完成或失败。返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。
实现 Promise.all
Promise.myAll = function (iterable) {
return new Promise((resolve, reject) => {
if (typeof Object(iterable)[Symbol.iterator] === 'undefined') {
// 没有 Symbol.iterator 接口
const type = Object.prototype.toString.call(iterable).slice(8, -1).toLowerCase();
throw new Error(`${
type} ${
iterable.toString()} is not iterable (cannot read property Symbol(Symbol.iterator))`)
}
const array = [...iterable]; // 将可迭代对象转数组并用来保存运行结果
const allNum = array.length;
if (!allNum) return resolve([]);
const values = []; // 保存运行结果
let cnt = 0; // 保存成功的次数
array.forEach((item, index) => {
Promise
.resolve(item) // 可以将非 promise 转化
.then(res => {
cnt++;
values[index] = res;
if (cnt === allNum) resolve(values);
})
.catch(err => reject(err)); // 如果失败了将返回第一个失败的结果
});
})
}
功能测试
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 3000, 'foo');
});
Promise
.myAll([p1, p2, p3])
.then(console.log); // [3, 1337, 'foo']
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(reject, 3000, 'foo');
});
Promise
.myAll([p1, p2, p3])
.then(values => console.log(values))
.catch(console.log); // 'foo'
Promise.myAll('123').then(console.log); // [ '1', '2', '3' ]
Promise.myAll([]).then(console.log); // []
Promise.myAll(666).then(console.log); // Error: number 666 is not iterable (cannot read property Symbol(Symbol.iterator))