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

作者: 竹叶寨少主 | 来源:发表于2021-04-02 17:09 被阅读0次

        在上篇中,我们已经实现了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 < promises.length; i++) {
          if (isPromise(promises[i])) {
            promises[i].then(
              (res) => {
                //得知对象的状态是成功,则将当前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 < promises.length; i++) {
          // 非Promise先转化为Promise
          if (!(promises[i] instanceof Promise)) {
            promises[i] = Promise.resolve(promises[i]);
          }
          promises[i].then(
            (v) => {
              //谁率先改变状态 返回值就是谁的结果
              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 < promises.length; i++) {
          if (!(promises[i] instanceof Promise)) {
            promises[i] = Promise.resolve(promises[i]);
          }
          promises[i].then(
            (res) => {
              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 < promises.length; i++) {
            if (promises[i] instanceof Promise) {
                try {
                    const res = await promises[i]
                    result[i] = {
                        status: 'Fulfilled',
                        value: res,
                      };
                } catch (reason) {
                    result[i] = {
                        status: 'Rejected',
                        reason,
                      };
                }
            } else {
              result[i] = {
                status: 'Fulfilled',
                value: promises[i],
              };
            }
          }
          resolve(result);
        });
      };
    

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

    相关文章

      网友评论

        本文标题:从0到1实现A+规范Promise(下篇)

        本文链接:https://www.haomeiwen.com/subject/wvlbhltx.html