实现一个Promise.all

最近面试老是被问到这个,所以记录一下

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

demo:

let p1 = new Promise((resolve, reject) => {
  resolve('成功了')
})

let p2 = new Promise((resolve, reject) => {
  resolve('success')
})

let p3 = Promse.reject('失败')

Promise.all([p1, p2]).then((result) => {
  console.log(result)               //['成功了', 'success']
}).catch((error) => {
  console.log(error)
})

Promise.all([p1,p3,p2]).then((result) => {
  console.log(result)
}).catch((error) => {
  console.log(error)      // 失败了,打出 '失败'
})

如何自己实现一个promise.all呢

1、如果传参对象为空

function myPromiseAll(arr) {
    // 定义一个数组
    let result = [];

    return new Promise((resolve, reject) => {

        // 现在只考虑 “在完成情况下” ,会返回一个数组
        resolve(result);
       
        
    });
}

let pResult = myPromiseAll([]);
pResult.then(value=>{
    console.log(pResult);  // 输出 Promise { <state>: "fulfilled", <value>: [] }
    console.log(value); // 输出:[]
})

2、如果传参对象不是promise

function myPromiseAll(arr) {
    let result = [];

    return new Promise((resolve, reject) => {

        for(let i = 0; i < arr.length; i++) {
            result.push(arr[i]);
        }

        resolve(result);
       
        
    });
}


let pResult = myPromiseAll([1,2,3]);  // 元素不是Promise实例
pResult.then(value=>{
    console.log(pResult); // 输出:  Promise { <state>: "fulfilled", <value>: (3) […] }
    console.log(value); // 输出: Array(3) [ 1, 2, 3 ]
})

3、综合所有情况

function myPromiseAll(arr) {
    let result = [];

    return new Promise((resolve, reject) => {

        // 数组为空,直接resolve了
        if(arr.length == 0) {
            resolve(result);
        }


        for(let i = 0; i < arr.length; i++) {
            
            if(arr[i].then) { // 若元素是Promise实例,则会有then函数,这里只是简单的作为判断标准
                
                // 元素是Promise
                arr[i].then(value => {
                    console.log(value);
                    result[i] = value;

                    // 想一想什么时候resolve呢?--- 所有Promise实例都完成了
                    if(result.length == arr.length) {
                       console.log("所有都完成了")
                        resolve(result);
                    }

                })
                
            } else {
                result.push(arr[i]);

                // 这段代码跟上面重复,想想,能不能提取放到外面,会出现什么情况呢?
                if(result.length == arr.length) {
                    resolve(result);
                }

            }
        } 

    });
}

let p1 = new Promise((resolve, reject)=> {
    setTimeout(resolve, 2000, "P1 resolved");
})

let p2 = new Promise((resolve, reject)=> {
    setTimeout(resolve, 3000, "P2 resolved");
})

let p3 = new Promise((resolve, reject)=> {
    setTimeout(resolve, 4000, "P3 resolved");
})


let pResult = myPromiseAll([p1,p2,p3]);
pResult.then(value=>{
    console.log(pResult);
    console.log(value);
})

// 输出
// P1 resolved 
// P2 resolved
// P3 resolved
// 所有都完成了
// Promise { <state>: "fulfilled", <value>: (3) […] }
// Array(3) [ "P1 resolved", "P2 resolved", "P3 resolved" ]

 4、如何传入的promise中有失败的呢?

function myPromiseAll(arr) {
    let result = [];

    return new Promise((resolve, reject) => {

        // 如果数组为空,直接返回空数组
        if(arr.length == 0) {
            resolve(result);
        }


        for(let i = 0; i < arr.length; i++) {
            
            if(arr[i].then) { // 若元素是Promise实例,则会有then函数,这里只是简单的作为判断标准
                
                // 元素是Promise
                arr[i].then(value => {
                    console.log(value);
                    result.push(value);

                    // 想一想什么时候resolve呢?
                    if(result.length == arr.length) {
                        console.log("所有都成功了")
                        resolve(result);
                    }

                }, err => {
                    console.log("很不幸,其中一个失败了");
                    // 注意到没, 这里没有像上面的判断 result.length == arr.length, 为什么?
                    // 只要碰到 resolve 或 reject ,就结束了
                    reject(err);
                })
                
            } else {
                result.push(arr[i]);

                // 这段代码跟上面重复,想想,能不能提取放到外面,会出现什么情况呢?
                if(result.length == arr.length) {
                    resolve(result);
                }

            }
        } 

    });
}

let p1 = new Promise((resolve, reject)=> {
    setTimeout(reject, 2000, "P1 rejected");
})

let p2 = new Promise((resolve, reject)=> {
    setTimeout(resolve, 3000, "P2 resolved");
})

let p3 = new Promise((resolve, reject)=> {
    setTimeout(resolve, 4000, "P3 resolved");
})


let pResult = myPromiseAll([p1,p2,p3]);
pResult.then(value=>{
    console.log(pResult);  // 是输出成功
    console.log(value);
}, err => {
    console.log(pResult);   // 还是输出失败呢?
    console.log(err);
})

// 输出
// 很不幸,其中一个失败了
// Promise { <state>: "rejected" }
// P1 rejected
// P2 resolved
// P3 resolved

知乎上看到的一个简单的方法

Promise.prototype.all = function(promises) {
  let results = [];
  let promiseCount = 0;
  let promisesLength = promises.length;
  return new Promise(function(resolve, reject) {
    for (let val of promises) {
      Promise.resolve(val).then(function(res) {
        promiseCount++;
        // results.push(res);
        results[i] = res;
        // 当所有函数都正确执行了,resolve输出所有返回结果。
        if (promiseCount === promisesLength) {
          return resolve(results);
        }
      }, function(err) {
        return reject(err);
      });
    }
  });
};

 

  

上一篇:【前端面试题】事件循环event_loop


下一篇:Promise