Promise.all原理
官网:Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个Promise实例,那个输入的所有 promise 的 resolve 回调的结果是一个数组。这个Promise的 resolve 回调执行是在所有输入的 promise 的 resolve 回调都结束,或者输入的 iterable 里没有 promise 了的时候。它的 reject 回调执行是,只要任何一个输入的 promise 的 reject 回调执行或者输入不合法的 promise 就会立即抛出错误,并且 reject 的是第一个抛出的错误信息。
在实现之前我们先弄清楚promise.all的特点
let fn1 = new Promise((resolve, reject) => {
throw('fn1出错了')
})
let fn2 = new Promise((resolve, reject) => {
reject('fn2出错了')
})
let fn3 = new Promise((resolve, reject) => {
resolve('fn3成功了')
})
let fn4 = new Promise((resolve, reject) => {
resolve('fn4成功了')
})
let fn5 = '我是fn5'
Promise.all([fn4, fn3, fn5]).then(res => {
console.log(res) // ['fn3成功了', 'fn4成功了', '我是fn5']
}).catch(err => {
console.log(err)
})
Promise.all([fn1, fn2, fn3, fn4, fn5]).then(res => {
console.log(res)
}).catch(err => {
console.log(err) // fn1出错了
})
看到上面的demo,我们至少可以得出下面几个结论:
- Promise.all()生成的对象的状态是由数组中的Promise对象[fn1, fn2, fn3, fn4, fn5]决定的;当每个promise对象的状态为resolve的时候,fn3, fn4, fn5三个Promise对象产生的结果会组成一个数组返回返回给Promise.all生成的对象
- 如果fn1, fn2, fn3, fn4, fn5中有一个Promise对象变为rejected状态的话,romise.all生成的对象也会变成rejected状态,第一个被rejected的对象的返回值会被返回出来
如何自己实现一个promise.all呢
function isPromise(val){
return val && typeof val.then ==='function'
}
function promiseAll (promises) {
return new Promise((resolve, reject) => {
let result = []
let flag = 0
function next() {
let newFn = promises.slice(flag, flag + 1)[0]
carry(newFn, flag++)
}
next()
function carry (fn, i) {
// 判断fn是否是Promise对象
let f = isPromise(fn) ? fn : Promise.resolve(fn)
f.then(res => {
result[i] = res
// 如果全部是resolve状态,那就resolve出去result
if (flag === promises.length) {
return resolve(result)
}
next()
}).catch(err => {
return reject(err) //有异常直接reject出来
})
}
})
}
promiseAll([fn3, fn4, fn5]).then(res => {
console.log(res) // ['fn3成功了', 'fn4成功了', '我是fn5']
}).catch(err => {
console.log(err)
})
promiseAll([fn3, fn4, fn2, fn5]).then(res => {
console.log(res)
}).catch(err => {
console.log(err) // fn2出错了
})
以上就是实现promise.all的全部代码,我们实际开发中经常会碰到另外一个需求:
同时执行后端的多个接口,不管成功与否都要对应的返回出来,那么该怎么做呢?
function promiseAll (promises) {
let results = [];
let promiseCount = 0; // 用来计算参数中有没有被执行完
let len = promises.length;
return new Promise((resolve ,reject) => {
promises.forEach((item, index) => {
item.then(res => {
results[index] = res
promiseCount++
if(promiseCount === len){
resolve(results)
}
}).catch(err => {
results[index] = err
promiseCount++
if(promiseCount === len){
resolve(results)
}
})
})
})
}
总结
-
始终围绕Promise.all几个特点解读
- Promise.all()接受一个 Array 类型的参数
- 只有数组中全部的 Promise 都变为 resolve 的时候,返回一个新的 Promise 实例
- 只要有一个失败,状态就变成 rejected
-
同时当面试官问你如何实现promise.all的时候,你可以把上面这两种情况都表达出来,面试官会眼前一亮,觉得你思维很缜密,可以加分不少哦