一、手写promise.all
先总结下promise.all用法的特点:
- 接收一个
Promise
实例的数组或具有Iterator
接口的对象,- 如果元素不是
Promise
对象,则使用Promise.resolve
转成Promise
对象- 如果全部成功,状态变为
resolved
,返回值将组成一个数组传给回调- 只要有一个失败,状态就变为
rejected
,返回值将直接传递给回调all()
的返回值也是新的Promise
对象
1. 具体代码
代码逻辑:
- 判断传入形参是否合法,非法形参直接返回空集合。
- 定义用于记录执行次数的变量和返回结果集。
- 循环遍历执行
3.1 考虑可能是普通对象,使用 Promise.resolve对单次循环对象进行封装处理。
3.2 将每次执行结果放入定义的结果集中。
3.3 自加记录执行数 等于 循环次数,返回结果集
3.4 任何一个Promise对象执行失败,则调用reject()方法
es5写法:
Promise.all1 = function(iterators) {
return new Promise((resolve, reject) => {
if (!iterators || iterators.length === 0) {
resolve([])
} else {
// 计算器,用于判断所有任务是否执行完成
var count = 0;
// 结果数组
var result = [];
// 执行数组长度
var len = iterators.length
for(var i = 0; i < len; i++) {
// 利用IIFE来完成变量i的锁定
(function(i) {
// 考虑到iterators[i]可能是普通对象,则统一包装为Promise对象
Promise.resolve(iterators[i]).then( (data) => {
// 按顺序保存对应的结果
result[i] = data;
// 判断++count 的次数是否等于 传入执行数组的长度
if (++count === len) {
resolve(result);
}
}, (err) => {
// 任何一个Promise对象执行失败,则调用reject()方法
reject(err);
})
})(i)
}
}
})
}
es6写法:
Promise.all2 = function(iterators) {
return new Promise((resolve, reject) => {
if (!iterators || iterators.length === 0) {
resolve([])
} else {
// 计算器,用于判断所有任务是否执行完成
let count = 0;
// 结果数组
let result = [];
// 执行数组长度
let len = iterators.length
for(let i = 0; i < len; i++) {
// 考虑到iterators[i]可能是普通对象,则统一包装为Promise对象
Promise.resolve(iterators[i]).then( (data) => {
// 按顺序保存对应的结果
result[i] = data;
// 判断++count 的次数是否等于 传入执行数组的长度
if (++count === len) {
resolve(result);
}
}, (err) => {
// 任何一个Promise对象执行失败,则调用reject()方法
reject(err);
})
}
}
})
}
测试代码:
const f1 = new Promise( (resolve,reject) => {
console.log('enter f1')
resolve('f1')
})
const f2 = new Promise( (resolve,reject) => {
console.log('enter f2')
reject('err')
})
const f3 = new Promise( (resolve,reject) => {
console.log('enter f3')
resolve('f3')
})
Promise.all2([f1, f2, f3]).then( data => {
console.log(data)
}).catch(err => {
console.log(err)
})