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

    在上篇中,我们已经实现了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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容