如何手动实现一个Promise.all

我相信有些同窗在面试的过程当中,面试官会问你可否简单描述一下Promise.all的原理,小编我也是被问到,因而也在网上找了几遍文章和例子,看完以后也是死恍然大悟,但愿能帮到小伙伴们git

Promise.all原理

Promise.all 接收一个 promise 对象的数组做为参数,当这个数组里的全部 promise 对象所有变为resolve或 有 reject 状态出现的时候,它才会去调用 .then 方法,它们是并发执行的github

在实现以前先解读promise.all 的特色

一、Promise.all()方法将多个Promise实例包装成一个Promise对象(p),接受一个数组(p1,p2,p3)做为参数,数组中不必定须要都是Promise对象,可是必定具备Iterator接口,若是不是的话,就会调用Promise.resolve将其转化为Promise对象以后再进行处理。面试

二、使用Promise.all()生成的Promise对象(p)的状态是由数组中的Promise对象(p1,p2,p3)决定的;数组

  • 一、若是全部的Promise对象(p1,p2,p3)都变成fullfilled状态的话,生成的Promise对象(p)也会变成fullfilled状态,p1,p2,p3三个Promise对象产生的结果会组成一个数组返回给传递给p的回调函数;
  • 二、若是p1,p2,p3中有一个Promise对象变为rejected状态的话,p也会变成rejected状态,第一个被rejected的对象的返回值会传递给p的回调函数。

Promise.all()方法生成的Promise对象也会有一个catch方法来捕获错误处理,可是若是数组中的Promise对象变成rejected状态时,而且这个对象还定义了catch的方法,那么rejected的对象会执行本身的catch方法,而且返回一个状态为fullfilled的Promise对象,Promise.all()生成的对象会接受这个Promise对象,不会返回rejected状态promise

版本一

function PromiseAll(arr) {
    //PromiseAll的返回值为一个promise对象
    return new Promise((resolve, reject) => {
        //PromiseAll的入参必须是数组
        if (!Array.isArray(arr)) {
            return reject(new TypeError('arr must be an array.'));
        }
        let resArr = [];
        for (let i in arr) {
            (function(i) {
                Promise.resolve(arr[i]).then(res => {
                    resArr.push(res);
                    //只有全部的都成功了,才会返回resolve
                    if (i == arr.length - 1) {
                        return resolve(resArr);
                    }
                }, err => {
		    // 只要出错就抛出
                    return reject(err)
                }).catch(err => {
                    console.log(err)
                })
            })(i)
        }
    })
}

//测试
const pro1 = new Promise((res,rej) => {
  setTimeout(() => {
    res('1')
  },1000)
})
const pro2 = new Promise((res,rej) => {
  setTimeout(() => {
    res('2')
  },2000)
})
const pro3 = new Promise((res,rej) => {
  setTimeout(() => {
    res('3')
  },3000)
})

const proAll = PromiseAll([pro1,pro2,pro3])
.then(res => 
  console.log(res) // 3秒以后打印 ["1", "2", "3"]
)
.catch((e) => {
  console.log(e)
})
复制代码

版本二

function PromiseAll(promiseArrs) {
  return new Promise((resolve, reject) => { //返回一个新的Promise
    let arr = []; //定义一个空数组存放结果
    let i = 0;
    function handleData(index, data) { //处理数据函数
        arr[index] = data;
        i++;
        if (i === promiseArrs.length) { //当i等于传递的数组的长度时 
            resolve(arr); //执行resolve,并将结果放入
        }
    }
    for (let i = 0; i < promiseArrs.length; i++) { //循环遍历数组
        promiseArrs[i].then((data) => {
            handleData(i, data); //将结果和索引传入handleData函数
        }, reject)
    }
 })
}

// 测试
const pro1 = new Promise((res,rej) => {
  setTimeout(() => {
    res('1')
  },1000)
})
const pro2 = new Promise((res,rej) => {
  setTimeout(() => {
    res('2')
  },2000)
})
const pro3 = new Promise((res,rej) => {
  setTimeout(() => {
    res('3')
  },3000)
})

const proAll = PromiseAll([pro1,pro2,pro3])
.then(res => 
 console.log(res) // 3秒以后打印 ["1", "2", "3"]
)
.catch((e) => {
 console.log(e)
})
复制代码

版本三

function PromiseAll(promiseArray) {
  return new Promise(function(resolve,reject){
    //判断参数类型
    if(!Array.isArray(promiseArray)){
        return reject(new TypeError('arguments muse be an array'))
    }
    var counter = 0,
        promiseNum = promiseArray.length,
        resolvedArray = new Array(promiseNum);
    for(var i = 0; i < promiseNum; i++){
        (function(i){
            Promise.resolve(promiseArray[i]).then(function(value){
                counter++;
                resolvedArray[i] = value;
                if(counter == promiseNum){
                    return resolve(resolvedArray)
                }
            },function(reason){
                return reject(reason)
            })
        })(i)
    }
 })
}

// 测试
const pro1 = new Promise((res,rej) => {
  setTimeout(() => {
    res('1')
  },1000)
})
const pro2 = new Promise((res,rej) => {
  setTimeout(() => {
    res('2')
  },2000)
})
const pro3 = new Promise((res,rej) => {
  setTimeout(() => {
    res('3')
  },3000)
})

const proAll = PromiseAll([pro1,pro2,pro3])
.then(res => 
 console.log(res) // 3秒以后打印 ["1", "2", "3"]
)
.catch((e) => {
 console.log(e)
})
复制代码

总结

无论版本如何变更,只要围绕Promise.all几个特色解读就能够并发

  1. Promise.all()接受一个 Array 类型的参数
  2. 只有数组中所有的 Promise 都变为 resolve 的时候
  3. 返回一个新的 Promise 实例
  4. 只要有一个失败,状态就变成 rejected

更多关于Promise.all文章

介绍下 Promise.all 使用、原理实现及错误处理
手动实现一个 Promise.all()
实现promise.all方法
函数

关于我

相关文章
相关标签/搜索