手写Promise.all()

7,763 阅读2分钟

前言

个人总结,仅供参考。

面试官问:你了解Promise吗?用的多吗?

如果你说了解,用的多,面试官基本上不会叫你手写Promise/A+规范,因为面试一般在1小时左右,手写Promise/A+会花费很长的时间;所以可能会让你手写Promise的静态方法。

Promise.all()

面试官问: 你知道Promise.all吗?

你可能回答:Promise.all接收一个数组,数组里面都是promise。

这时候,面试官反问:数组里面真的都是promise吗?

面对面试官的质疑,你可能会反应过来:里面也不全都是promise,也可以是常量。


面试官问: 它的执行情况是怎么回事呢?

你的回答:等到里面的promise全部执行完成后,才会返回结果。

面试官问: 如果里面有一个执行失败了呢?

你的回答:它会在catch里面捕获。

面试官又问:那其他的还会执行吗?

这时候你可能不会了。 答案是:会的,因为promise在实例化时,就执行了;.then()只是用来看它的结果。


既然你知道这么多promise的东西,那你就手写一下Promise.all吧。然后他会叫你补充代码...
function PromiseAll(promiseArray) {
    //请在此处补全代码
}


const p1 = new Promise((res, rej) => {
    setTimeout(() => {
        res('p1')
    }, 1000)
})

const p2 = new Promise((res, rej) => {
    setTimeout(() => {
        res('p2')
    }, 2000)
})

const p3 = new Promise((res, rej) => {
    setTimeout(() => {
        res('p3')
    }, 3000)
})

const test = PromiseAll([p1, p2, p3])
    .then(res => console.log(res))
    .catch(e => console.log(e))

console.log(test);

手写代码的坑

1.很多人不知道需要返回一个Promise对象,

function PromiseAll(promiseArray) {    //返回一个Promise对象
   return new Promise((resolve, reject) => {   
   
   })
}

2.最好判断一下传入的参数是否为数组,

function PromiseAll(promiseArr) {             //返回一个Promise对象
   return new Promise((resolve, reject) => {
       if(!Array.isArray(promiseArr)) {          //判断一下传入的参数是否为数组
           return reject(new Error('传入的参数不是数组!'))
       }
      
       const res = []
       for(let i = 0; i < promiseArr.length; i++) {
           
       }
   })
}

3.有很多人会分别判断数组里面的promise和常量, 但是里面的顺序会乱


function PromiseAll(promiseArr) {             //返回一个Promise对象
   return new Promise((resolve, reject) => {
       if(!Array.isArray(promiseArr)) {          //判断一下传入的参数是否为数组
           return reject(new Error('传入的参数不是数组!'))
       }
      
       const res = []
       for(let i = 0; i < promiseArr.length; i++) {
           const isPromise = Object.prototype.toString.call(promiseArr[i] === '[Object Promise]')
           // if(isPromise) {
           //     promiseArr[i].then(result => res.push(result))
           // } else {
           //     res.push(promiseArr[i])
           // }
           
           //用promise包装
           
             Promise.resolve(promiseArr[i]).then(value => {
             res.push(value)
             if (res.length === promiseArr.length) {
                 resolve(res)
             }
        })
       }
   })
}


优化后的答案

function PromiseAll(promiseArray) {    //返回一个Promise对象
     return new Promise((resolve, reject) => {
     
        if (!Array.isArray(promiseArray)) {                        //传入的参数是否为数组
            return reject(new Error('传入的参数不是数组!'))
        }

        const res = []
        let counter = 0                         //设置一个计数器
        for (let i = 0; i < promiseArray.length; i++) {
            Promise.resolve(promiseArray[i]).then(value => {
                counter++                  //使用计数器返回 必须使用counter
                res[i] = value
                if (counter === promiseArray.length) {
                    resolve(res)
                }
            }).catch(e => reject(e))
        }
    })
}