20 道常考手写题(中) - Promise 篇

76 阅读2分钟

1. Promise.all

Promise.all

Promise.all() 方法接收一个 promiseiterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个 Promise 实例, 那个输入的所有 promiseresolve 回调的结果是一个数组。这个 Promiseresolve 回调执行是在所有输入的 promiseresolve 回调都结束,或者输入的 iterable 里没有 promise 了的时候。

Promise.myAll = function (promises) {
  const values = []; //放置结果
  let count = 0; // 记录fullfilled的promise个数
  //传入的promises为可迭代对象,不一定为数组
  promises = Array.from(promises);
  let len = promises.length;
  // 需要判断下数组length是否为0,如果为0,则
  // forEach不会执行传递的函数,导致promise状态永远为pendding
  // 所以要返回一个为fulfilled状态的promise
  if (len === 0) {
    return Promise.resolve([]);
  }
  return new Promise((resolve, reject) => {
    promises.forEach((p, i) => {
      Promise.resolve(p)
        .then((res) => {
          values[i] = res; // 传递的promsie数组和结果要一一对应
          if (++count === len) {
            //是否所有的promise都进入fullfilled状态
            resolve(values); //返回结果
          }
        })
        .catch((e) => {
          reject(e); //如果有一个错误,直接reject并传递 reason
        });
    });
  });
};

2. Promise.race

Promise.all差不多,但race只返回第一个执行成功或者失败的promise

Promise.myRace = function (iterable) {
  // 转换可迭代对象 iterable为 数组
  promises = Array.from(iterable);
  return new Promise((resolve, reject) => {
    promises.forEach((p) => {
      Promise.resolve(p)
        .then((res) => {
          resolve(res);
        })
        .catch((e) => {
          reject(e);
        });
    });
  });
};

3. generatorToAsync(co)

为了解决 Promise 的问题,asyncawait 在 ES7 中被提了出来,是目前为止最好的解决方案

co是著名程序员 TJ Holowaychuk 于 2013 年 6 月发布的一个小工具,用于 Generator 函数的自动执行。它是用来解决异步操作的开源项目 ,也是后来 JavaScript 异步操作的终极解决方案—— async/await 的先驱。

很多人都知道 asyncawaitgenerator 的语法糖,但是不知道其原理,实际上async就是官方实现的co.

下面的generatorToAsync函数可以把一个generator类似转换为于一个async函数,当调用generatorToAsync返回的那个函数时,会自执行 generator.

function generatorToAsync(generatorFn) {
  return function () {
    const gen = generatorFn.apply(this, arguments);
    //  返回一个promise
    return new Promise((resolve, reject) => {
      //定义step 函数,用于 自执行generator
      // ret:  key为next时,ret 相当于await返回的值;key为throw,ret为promise执行报错信息
      function step(key, ret) {
        let generatorResult = null;
        // 捕获 gen.next ,gen.throw  执行可能报错,报错的话直接reject掉
        try {
          generatorResult = gen[key](ret);
        } catch (err) {
          //报错,return 后面不用再执行了
          return reject(err);
        }

        const { value, done } = generatorResult;
        // 若 done 为 true,则说明genertor函数执行完,这时value为genertor的return值
        if (done) {
          return resolve(value);
        } else {
          // value 不一定为promise,也可以为不同对象或值,所以用Promise.resolve包裹一下,转为promise对象
          Promise.resolve(value).then(
            (res) => {
              // 正常返回值,继续执行genertor
              step("next", res);
            },
            (err) => {
              // gen.throw 强制 抛出错误 , 让generator 函数中的try catch 可以捕获 错误
              step("throw", err);
            }
          );
        }
      }
      step("next");
    });
  };
}