从0到1实现A+规范Promise(下篇)

时间:2021-6-12 作者:qvyue

    在上篇中,我们已经实现了Promise的基本功能及then,catch两个实例方法。下面我们来实现ES6中的Promise对象的所有实例方法与静态方法。

源码地址,欢迎star🤭

  • Promise.prototype.finally()

    该方法不论 Promise 对象最后状态如何,都会执行传入的回调。
关于该方法的实现有两点要说明
1.finally方法的回调不接收任何参数,这表明该回调的执行不依赖Promise的状态和结果。
2.finally不会阻止结果的传递。即如果finally方法之后还有链式调用的then或catch方法,则会继续调用。因此finally方法应该返回一个Promise,其结果和状态就是调用finally方法的Promise的状态和结果。这里很自然的可以想到使用then方法,因为then方法特性恰好符合前面所述,因此finally方法实质上是then方法的特例。

Promise.prototype.finally = function (onFinished) {
  return this.then((val) => {
    onFinished();
    return val;
  },(reason) => {
    onFinished();
    throw reason
  });
};
  • Promise.resolve()

    该方法返回一个promise对象,结果和状态由入参决定。

Promise.resolve = function (value) {
  //返回promise对象
  return new Promise((resolve, reject) => {
    if (value instanceof Promise) {
      value.then(
        (res) => {
          resolve(res);
        },
        (reason) => {
          reject(reason);
        }
      );
    } else {
      //状态设置为成功
      resolve(value);
    }
  });
};
  • Promise.reject()

    该方法返回一个状态为 rejected的Promise 实例,无论入参是什么,返回的实例的状态总是rejected。

Promise.reject = function (reason) {
  return new Promise((resolve, reject) => {
    reject(reason);
  });
};

  • Promise.all()

    该方法接受一个由Promise实例组成的数组作为参数,返回一个Promise。该Promise状态有两种情况,我们将Promise实例组成的数组暂且称为arr,all返回的Promise称为p。
1.只有arr所有成员的状态都变成fulfilled,p的状态才会变成fulfilled,且其结果为arr所有成员的结果。
2.只要arr中有一个成员的状态变为reject,则p的状态立即变为rejected,且其结果就是那个状态变为reject的成员的结果。

// 判断是否是promise
let isPromise = (x) => {
  if ((typeof x === "object" && x != null) || typeof x === "function") {
    if (typeof x.then === "function") {
      return true;
    }
  }
  return false;
};
Promise.all = function (promises) {
  //返回结果为promise对象
  return new Promise((resolve, reject) => {
    // 声明计数变量
    let count = 0;
    // 结果数组
    let arr = [];
    //遍历
    for (let i = 0; i  {
            //得知对象的状态是成功,则将当前promise对象成功的结果 存入到数组中
            count++
            // 这里不能用push ,因为我们要保证结果数组的顺序和传入的
            // promise数组的顺序一致。
            // 如果用push,则不能保证顺序,因为异步操作返回结果的快慢有所不同。
            arr[i] = res;
            // 只有全部promise均成功 all才成功
            if (count === promises.length) {
              //修改状态
              resolve(arr);
            }
          },
          (reason) => {
            // 对象的状态是失败,直接reject
            reject(reason);
          }
        );
      } else {
        // 非promise 直接推入结果数组
        count++;
        arr[i] = promises[i];
        if (count === promises.length) {
          resolve(arr);
        }
      }
    }
  });
};
  • Promise.race()

    方法接受一个由Promise实例组成的数组作为参数(arr),返回一个Promise(p)。该Promise状态和结果取决去arr中率先改变状态的成员,即p的状态和结果是率先改变状态的成员的状态和结果。
    如果arr的某个成员不是 Promise 实例,会将其先转为 Promise 实例,再进一步处理。

Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i  {
          //谁率先改变状态 返回值就是谁的结果
          resolve(v);
        },
        (r) => {
          //修改返回对象的状态为 『失败』
          reject(r);
        }
      );
    }
  });
};
  • Promise.any()

    该方法接受一个由Promise实例组成的数组作为参数(arr),返回一个Promise(p)。该方法的行为恰好与Promsie.all方法相反。只要arr有一个成员变成fulfilled状态,p就会变成fulfilled状态;当所有成员都变成rejected状态,p就会变成rejected状态。

Promise.any = function (promises) {
  return new Promise((resolve, reject) => {
    let count = 0;
    for (let i = 0; i  {
          resolve(res);
        },
        () => {
          count++;
          if (count === promises.length) {
            //该方法抛出的错误是一个 AggregateError 实例。
            //它相当于一个数组,每个成员对应一个被rejected的操作所抛出的错误。
            reject(new AggregateError([], "All promises were rejected"));
          }
        }
      );
    }
  });
};
  • Promise.allSettled()

    该方法接受一组 Promise 实例作为参数(arr),包装成一个新的 Promise 实例(p)。只有arr所有成员都返回结果,不管是fulfilled还是rejected,p才会结束。该方法返回的新的 Promise 实例,一旦结束,状态总是fulfilled,不会变成rejected。

Promise.allSettled = function (promises) {
    return new Promise(async (resolve) => {
      let result = [];
      for (let i = 0; i 

    至此,我们已经完成了A+规范的Promise及ES6中所有的实例方法与静态方法的实现。如果觉得对你有帮助,欢迎三连支持😀。
参考:https://es6.ruanyifeng.com/#docs/promise

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。