Fe-interview: 第 24 题:实现 Promise.all

Created on 19 Jun 2020  ·  6Comments  ·  Source: lgwebdream/FE-Interview

Promise.all = function (arr) {
  // 实现代码
};
JavaScript 头条 微医 有赞 滴滴 编程题

Most helpful comment

  /**
   * Promise.all
   * @description 当这个数组里的所有promise对象全部变为resolve状态的时候,才会resolve, 当有一个promise对象变为reject状态时,就不再执行直接 reject
   * @param {*} values promise对象组成的数组作为参数
   */

Promise.prototype.all = (values)=>{
  return new Promise((resolve,reject)=>{
      let resultArr = []
      let count = 0
      let resultByKey = (value,index)=>{
           resultArr[index] = value
           if(++count === values.length){
                resolve(resultArr)
           }
      }
      values.forEach((promise,index)=>{
         promise.then((value)=>{
            resultByKey(value,index)
         },reject)
      })
  })

}

All 6 comments

1) 核心思路

  • ①接收一个 Promise 实例的数组或具有 Iterator 接口的对象作为参数
  • ②这个方法返回一个新的 promise 对象,
  • ③遍历传入的参数,用Promise.resolve()将参数"包一层",使其变成一个promise对象
  • ④参数所有回调成功才是成功,返回值数组与参数顺序一致
  • ⑤参数数组其中一个失败,则触发失败状态,第一个触发失败的 Promise 错误信息作为 Promise.all 的错误信息。

2)实现代码
一般来说,Promise.all 用来处理多个并发请求,也是为了页面数据构造的方便,将一个页面所用到的在不同接口的数据一起请求过来,不过,如果其中一个接口失败了,多个请求也就失败了,页面可能啥也出不来,这就看当前页面的耦合程度了~

function promiseAll(promises) {
  return new Promise(function(resolve, reject) {
    if(!Array.isArray(promises)){
        throw new TypeError(`argument must be a array`)
    }
    var resolvedCounter = 0;
    var promiseNum = promises.length;
    var resolvedResult = [];
    for (let i = 0; i < promiseNum; i++) {
      Promise.resolve(promises[i]).then(value=>{
        resolvedCounter++;
        resolvedResult[i] = value;
        if (resolvedCounter == promiseNum) {
            return resolve(resolvedResult)
          }
      },error=>{
        return reject(error)
      })
    }
  })
}

// test
let p1 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(1)
    }, 1000)
})
let p2 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(2)
    }, 2000)
})
let p3 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(3)
    }, 3000)
})
promiseAll([p3, p1, p2]).then(res => {
    console.log(res) // [3, 1, 2]
})
  /**
   * Promise.all
   * @description 当这个数组里的所有promise对象全部变为resolve状态的时候,才会resolve, 当有一个promise对象变为reject状态时,就不再执行直接 reject
   * @param {*} values promise对象组成的数组作为参数
   */

Promise.prototype.all = (values)=>{
  return new Promise((resolve,reject)=>{
      let resultArr = []
      let count = 0
      let resultByKey = (value,index)=>{
           resultArr[index] = value
           if(++count === values.length){
                resolve(resultArr)
           }
      }
      values.forEach((promise,index)=>{
         promise.then((value)=>{
            resultByKey(value,index)
         },reject)
      })
  })

}

Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(promises)) {
            throw new Error('argument must be a array');
        }
        // 用来记录Promise成功的次数
        let resolveCount = 0,
            // 用来保存Promise成功的结果
            resolveDataList = [];
        for (let index = 0, len = promises.length; index < len; index++) {
            const p = promises[index];
            Promise.resolve(p).then(data => {
                resolveDataList[index] = data;
                // promise成功次数等于promises数组长度,则成功
                if (++resolveCount === len) {
                    resolve(resolveDataList);
                }
                // 有一个失败就失败
            }, reject);
        }
    });
}

Promise.race = (promises = []) => {
    return new Promise((resolve, reject) => {
        if (!Array.isArray(promises)) {
            throw new TypeError(`argument must be a array`);
        }
        for (const p of promises) {
            // 有一个成功就返回成功状态的promise
            // 有一个失败就返回失败状态的promise
            p.then(resolve, reject);
        }
    });
}


// Promise.finally() 最终的,无论如何finally中传递的回调函数 必须会执行,如果返回一个promise,会等待这个Promise执行完成
Promise.prototype.finally = function(callback){
    return this.then(res => {
        // 如果then方法返回一个Promise, 就会等待这个方法执行完毕,所以需要包装成Promise才能等待
        return Promise.resolve(callback()).then(() => res);
    }, err => {
        return Promise.resolve(callback()).then(() => {
            throw err;
        })
    });
}

let p1 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(1)
    }, 1000)
})
let p2 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(2)
    }, 2000)
})
let p3 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve(3)
    }, 3000)
})
Promise.all([p3, p1, p2]).then(res => {
    console.log(res) // [3, 1, 2]
});
Promise.myAll = function (arr) {
  const length = arr.length;
  let result = new Array(length);
  let count = 0;
  let succeedCount = 0;

  let resolveAllFn = null;
  let rejectAllFn = null;

  let someErr = null;

  function addcount() {
    count++;
    if (count === length) {
      succeedCount === length
        ? resolveAllFn(result)
        : rejectAllFn(someErr)
    }
  }

  for (const [i, p] of arr.entries()) {
    Promise.resolve(p).then((res) => {
      result[i] = res;
      succeedCount++;
      addcount();
    }, (err) => {
      someErr = err;
      addcount();
    })
  }

  return new Promise((rs, rj) => {
    resolveAllFn = rs;
    rejectAllFn = rj;
  })
}

Promise.myAll([
  new Promise(rs=>{
    setTimeout(() => {
      rs(0)
    }, 1000);
  }),
  Promise.resolve(1),
]).then((res) => {
  console.log(res);//[ 0, 1]
});

Promise.myAll([
  new Promise((_, rj)=>{
    setTimeout(() => {
      rj(0)
    }, 1000);
  }),
  Promise.resolve(1),
]).then(() => {},err=>{
  console.log(err); //0
});

Promise.all = (...promises) => {
  const results = [];

  const merged = promises.reduce(
    (acc, p) => acc.then(() => p).then(r => results.push(r)),
    Promise.resolve(null));

  return merged.then(() => results);
};

from: https://eddmann.com/posts/implementing-promise-all-and-promise-race-in-javascript/

Promise.all = async (promises) => {
  const results = [];
  for (promise of promises) {
    results.push(await promise);
  }

  return results;
};
Was this page helpful?
0 / 5 - 0 ratings