JS 简易模拟Promise.all

先来看下MDN关于该方法的定义

Promise.all() 方法接收一个promise的iterable类型的入参,如果输入的所有promise都被resolve(fuifulled),那么将返回一个Promise<Array>实例;如果其中有任何一个promise被reject(rejected),那么将会返回该条错误信息。
 
Code:
/**
 * 模拟Promise.all方法
 */
Promise._all = (function() {
    /**
     * 模拟实现
     * @param {Promise[]} promises
     * @return {Promise}
     */
    var miniPromiseAll = function(promises) {
        if (promises[Symbol.iterator] === undefined) {
            return Promise.reject('TypeError: 参数不合法!');
        }
        // 统一设定将promises参数的数据类型规范为数组
        promises = Array.prototype.slice.call(promises);
        // promises = [...promises];

        /**
         * 异步处理完成后的结果列表
         * @type {Promise[]}
         */
        var fulFilledList = [];

        /**
         * promises数组的长度
         * @type {number}
         */
        var n = promises.length;

        /**
         * 初始化时的自定义处理函数
         * @param {Function} resolveFn 
         * @param {Function} rejectFn 
         */
        var executor = function(resolveFn, rejectFn) {
            // 已兑现的数量
            var cnt = 0;
            for (var i = 0; i < n; i++) {
                (function(idx) {
                    Promise.resolve(promises[idx])
                        .then(function(res) {
                            // 根据当前的index索引进行填入,确保与原promises数组的次序相同
                            fulFilledList[idx] = res;
                            // 待所有数组元素都兑现后
                            if (++cnt === n) {
                                resolveFn(fulFilledList);
                            }
                        })
                        .catch(rejectFn);
                })(i);
            }
        };

        return new Promise(executor);
    };

    return miniPromiseAll;
})();

//// 测试用例
var promises = [
    // Promise item 1:
    Promise.resolve('a'),
    // Promise item 2:
    new Promise(function(resolve) {
      window.setTimeout(function() {
        resolve('b');
      }, 600);
    }),
    // Promise item 3(非Promise对象):
    'c',
    // Promise item 4:
    new Promise(function(resolve) {
      window.setTimeout(function() {
        resolve('d');
      }, 100);
    }),
];
  
/**
 * 测试结果的log函数
 * @param {*[]} result 
 */
var testLog = function(result) {
    console.log('Mini Promise.all result: ', result);
};
  
Promise._all(promises)
    .then(testLog)
    .catch(console.warn);

 

_模拟实现(2022年时的一段代码,废弃但保留):

/**
 * 模拟Promise.all
 * @param {Array} promises - Promise数组
 * @return {Promise}
 */
Promise._all = function(promises) {
  // 如果传入的不是可迭代对象
  if (promises[Symbol.iterator] === undefined) {
    return Promise.reject('"promises" is not iterable (cannot read property Symbol(Symbol.iterator))');
  }
  // 异步的完成结果容器
  const fulfilledList = [];

  return new Promise((resolve, reject) => {
    // 使用for...of迭代promises
    for (const p of promises) {
      // 对promises数组中的元素进行Promise包裹,保证其为promise对象
      Promise.resolve(p)
        .then(res => {
          // 异步状态顺利完成后,将结果推入容器
          fulfilledList.push(res);
          // 如果元素数量与promises的容量相等就可以返回了
          if (fulfilledList.length === promises.length) {
            resolve(fulfilledList);
          }
        })
        // 任何一个元素出现失败状态则reject
        .catch(err => reject(err));
    }
  });
};

//// 测试代码 ----
var p1 = 1;
var p2 = new Promise(resolve => {
  window.setTimeout(() => {
    resolve('2');
  }, 400);
});
var p3 = Promise.resolve(3);

Promise._all([p1, p2, p3])
  .then(ans => {
    console.log(ans);
  })
  .catch(err => {
    console.warn(err);
  });

 

 

end

 

posted @ 2022-03-14 19:19  樊顺  阅读(130)  评论(0编辑  收藏  举报