上节课我们已经实现了Promise的基本结构,两大属性,并且实现了对Promise的状态和结果的修改,而且也实现then方法指定回调函数,并对同步异步任务的回调执行分别做了相应的介绍,最后对Promise指定多个回调也做了相应的实现与分析。

上节课虽然内容很多,但是依然还有一部分因为篇幅的问题,我们还没有介绍到,那么接下来,我们将对另外一部分的功能实现来做进一步的介绍。

同步任务then方法返回结果

我们之前的内容中就已经介绍过,Promise对象调用then方法返回的结果将会是一个新的Promise对象。那么我们目前的情况的话有没有实现这一功能呢?我们来测试一下:

let p = new Promise(
  (resolve, reject) => resolve("OK")
);
let result = p.then(
  value => console.log(value),
  reason => console.warn(reason)
);
console.log(result);

我们来看这段代码,首先我们实例化一个Promise对象,在这个对象中我们封装的是一个同步任务,然后调用then方法来指定回调,并且声明一个result变量来接收then方法的返回值,并且把返回值输出到控制台,那么我们来看一下结果:

image-20220315203846053

控制台中输出的是一个undefined,为什么呢?因为我们定义了then方法,但是我们的then方法并没有返回值,所以说默认返回的就是一个undefined

那么我们先来回顾一下then方法返回一个新的Promise对象的设计哲学是什么样子的:

  • then方法返回的Promise对象是一个新的Promise对象
  • then方法返回的Promise对象的状态和结果都取决于回调函数执行的结果
  • 回调函数执行的结果分为三种情况
  • 返回非Promise类型数据,then方法将返回一个成功的Promise对象,结果值为回调函数的返回值
  • 返回Promise对象,then方法将返回一个状态和结果值都与回调函数返回值一直的Promise对象
  • 抛出异常,then方法将返回一个失败的Promise对象,结果值为异常字符串

那么我们来修改一下代码吧,首先返回一个新的Promise对象:

Promise.prototype.then = function (onResolved, onRejected) {
  return new Promise((resolve, reject) => {
    if (this.PromiseState === "fulfilled") {
      onResolved(this.PromiseResult);
    }
    if (this.PromiseState === "rejected") {
      onRejected(this.PromiseResult);
    }
    if (this.PromiseState === "pending") {
      this.callbacks.push({ onResolved, onRejected });
    }
  });
};

我们用最简单的方法就直接在return的时候new一个新的Promise对象。但是我们之前then方法中的代码还是要执行的啊,那么就应执行器函数来包裹住之前的代码,可能有人会问,我们能不能把之前代码放在return之前呢?就目前来说是没有问题的,因为之前then方法中的内部代码也都是同步代码,那么在return之前或者是用执行器函数包裹住都没有区别,因为执行器函数也是立即同步被执行的。我们来看一下结果是什么样:

image-20220315205353716

我们看到控制台中输出的不再是undefined了,而是一个Promise对象,那么现在我们实现了第一条,then方法返回的是一个新的Promsie对象。但是有一点,我们这里输出的Promise对象的状态和结果值好像都有点问题。

我们来看我的第二条,then方法返回的Promise对象的状态和结果值都取决于回调函数的执行结果。那么我们来看一下我们的回调函数是什么,我们执行的是value => console.log(value),首先这个函数没有返回值,其次,控制台上也成功输出了value,说明回调函数没有抛出异常。

那么好,我们来看一下第三条,有三种情况,那么这属于那种情况呢?没有返回值就是undefined,而且也没有抛出异常,是不是刚好就是第一种情况,返回了非Promise类型的数据?那么我们就应该返回一个成功的Promise对象,而且结果值为回调函数的返回值,也就是undefined,那么我们再来修改一下代码:

Promise.prototype.then = function (onResolved, onRejected) {
  return new Promise((resolve, reject) => {
    if (this.PromiseState === "fulfilled") {
      let result = onResolved(this.PromiseResult);
      resolve(result);
    }
    if (this.PromiseState === "rejected") {
      let result = onRejected(this.PromiseResult);
      reject(result);
    }
    ...
  });
};

我们来看这段代码是什么意思呢?根据Promise设计哲学的第二条,then方法返回的Promise对象的状态和结果值由回调函数的执行结果来决定。

我们在第一步实例化的Promise对象p的状态是个什么状态?是不是一个成功的Promise?那么在调用then方法的时候是不是一定会根据状态去调用onResolved函数?这个onResolved函数是哪来的?是不是就是我们调用then方法时候传进去的,那么这里的话是不是就是value => console.log(vale)?那么这个函数的返回值是不是就应该是then方法返回的Promise对象的结果值?那么我们声明一个变量result来接收这个返回值。

那么接下来问题来了,我们结果值有了,但是then方法返回的Promise对象的状态我们该怎么修改呢?首先我们的then方法返回的是什么?是不是我们这里new出来的一个新的Promise?那么一个Promsie如果想改变状态要怎么做?这很简单啊,直接在执行器函数中去调用resolve或者reject函数就可以了,因为第一种情况永远返回的都是一个成功的Promise啊,这样我们调用resolve函数,并把result传进去一次性把状态和结果值都解决了。

所以说通过这一部分的分析,我们再回头来思考刚才的问题,我们then方法中的状态判断的这部分代码可以放在return之前吗?好像也可以,但是会比直接放在执行器函数中要麻烦许多。

那么我们现在再看一下结果:

image-20220315211916894

image-20220315212003423

我们看见了现在我们的输出好像还是有点问题,当我们第一步实例化的Promise的状态是rejected的话,我们是应该调用onRejected函数的,我们这里指定的onRejecte函数是什么?reason => console.warn(reason),这个回调函数也没有返回值啊,那么也是undefined,所以then方法返回的应该也是一个成功的Promise,但是我们输出的却是一个失败的Promise

不知道大家在看完上面那段代码的时候有没有发现一个错误,我这里先不说是什么错误,我先把代码修改一下:

Promise.prototype.then = function (onResolved, onRejected) {
  return new Promise((resolve, reject) => {
    if (this.PromiseState === "fulfilled") {
      let result = onResolved(this.PromiseResult);
      if (result instanceof Promise) {
        ...
      } else {
        resolve(result);
      }
    }
    if (this.PromiseState === "rejected") {
      let result = onRejected(this.PromiseResult);
      if (result instanceof Promise) {
        ...
      } else {
        resolve(result);
      }
    }
    ...
  });
};

大家来看这段代码,有没有发现和之前代码有什么不一样的地方?我们的回调函数的返回值是不是有两种情况?一种是Promise对象,另一种不是Promise对象,当不是Promise对象时,then方法将永远返回一个成功的Promsie,之前的代码中我们忘了做判断。

现在我们对回调函数的返回值的类型来做一个判断,当回调函数返回值不是一个Promise对象时,不论第一步实例化的Promise对象是否成功都调用resolve函数来改变新的Promise的状态和结果值。

image-20220315213947060

image-20220315214018505

那么如果回调函数返回的是一个Promise对象的话,又该怎么处理呢?我们知道如果回调函数返回的是一个Promsie对象的话那么这个Promsie对象的状态和结果值就是then方法返回的Promise对象的状态和结果值。那么我们应该怎么处理呢:

Promise.prototype.then = function (onResolved, onRejected) {
  return new Promise((resolve, reject) => {
    if (this.PromiseState === "fulfilled") {
      let result = onResolved(this.PromiseResult);
      if (result instanceof Promise) {
        result.then(
          value => resolve(value),
          reason => reject(reason)
        );
      } ...
    }
    if (this.PromiseState === "rejected") {
      let result = onRejected(this.PromiseResult);
      if (result instanceof Promise) {
        result.then(
          value => resolve(value),
          reason => reject(reason)
        );
      } ...
    }
    if (this.PromiseState === "pending") {
      this.callbacks.push({ onResolved, onRejected });
    }
  });
};

我们来看代码,这是什么操作呢?我们来想一下,如果回调函数返回的是一个Promise对象的话,那么这个Peomise对象是不是肯定可以调用then方法?那么是不是就代表着我们可以通过then方法来指定让这个Promise对象分别在成功和失败的时候来调用resolve函数和reject函数来修改then方法返回的Promsie对象的状态和结果值?

let result = p.then(
  value => {
    console.log(value);
    return new Promise((resolve, reject) => {
      resolve("OK")
    });
  },
  reason => {
    console.warn(reason);
    return new Promise((resolve, reject) => {
      reject("error");
    });
  }
);
console.log(result);

那么我们这次来让成功和失败的回调分别返回一个成功和失败的Promsie对象,我们再来看一下结果:

image-20220315215207192

第一步实例化的Promise对象是个成功的Promise,然后执行成功时的回调,回调函数返回一个成功的Promise对象,结果值是OK,我们看见控制台中输出的Promise对象的状态和结果值与回调函数返回的Promise对象一致。

image-20220315215521176

现在我们第一步实例化的Promise对象是一个失败的Promsie,然后执行失败时的回调,回调函数返回一个失败的Promise对象,结果值是error,我们看见控制台中输出的Promsie对象的状态和结果值与回调函数返回的Promise对象一直。

这样我们便实现了Promise设计哲学中then方法返回值规则的第一条,第二条以及第三条的前两种情况。

那么第三种情况呢?我再回调函数中抛出异常的话应该怎么处理呢?

Promise.prototype.then = function (onResolved, onRejected) {
  return new Promise((resolve, reject) => {
    if (this.PromiseState === "fulfilled") {
      try {
        let result = onResolved(this.PromiseResult);
        ...
      } catch (e) {
        reject(e);
      }
    }
    if (this.PromiseState === "rejected") {
      try {
        let result = onRejected(this.PromiseResult);
        ...
      } catch (e) {
        reject(e)
      }
    }
    ...
  });
};

为了节省篇幅我就把部分代码省略了,将之前的代码全部放在try代码块中,然后用catch来捕获回调函数中的异常,当回调函数中抛出异常时,将直接调用reject函数来修改状态。

image-20220315221214562

image-20220315221255879

以上便是对Promise同步任务调用then方法返回一个新的Promsie对象的实现。

异步任务then方法返回结果

我们前面说了同步任务的then方法返回结果。但是Promise异步任务的then方法返回情况,根据我们之前的经验来看肯定适合同步任务是不一样的,我们来回想一下我们之前让then方法调用回调函数的时候是什么情况?

  • 同步任务直接在then方法函数体中判断resolvedrejected状态,并直接执行回调
  • 异步任务在修改状态之前then方法已经完成调用,但是resolvedrejected状态都匹配不上,所以要在then方法中判断pending状态并保存传入的回调函数,然后在Promsie状态发生改变之后才执行回调函数

那么现在then的返回值情况我们来看一下是什么样子:

let p = new Promise(
  (resolve, reject) => setTimeout(
    () => resolve("OK"),
    1000
  )
);
let result = p.then(
  value => {
    console.log(value);
  },
  reason => {...}
);
console.log(result);

我们来看代码,我们实例化了一个Promise对象,并开启一个异步任务,让Promise对象延迟一秒将状态修改为成功,然后我们来看一下then方法返回的结果:

image-20220316095140755

我们发现返回的结果并不符合我们的预期,为什么呢?是不是和之前执行回调函数一样?因为执行then方法的时候我们还没有执行回调函数,那么就会去判断pending状态,但是pending状态中我们只是存储回调函数到我们第一步实例化的Promise对象上,而回调在执行的时候修改的也是我们第一步实例化的Promise对象的状态,所以说我们then方法返回的就是一个没有改变过状态还结果值的Promise对象。

那么我接下来的思路是不是就要在pending状态这个分支来做手脚了?那么我们怎么处理呢?

Promise.prototype.then = function (onResolved, onRejected) {
  return new Promise((resolve, reject) => {
    ...
    if (this.PromiseState === "pending") {
      this.callbacks.push({
        onResolved: () => {
          let result = onResolved(this.PromiseResult);
          if (result instanceof Promise) {

          } else {
            resolve(this.PromiseResult);
          }
        },
        onRejected: () => {...}
      });
    }
  });
};

我们来看代码,我们这里为了节省篇幅就把之前的代码省略了,我们来看对pending状态的判断分支,首先最外层我们依然还是哪个操作,我们要把回调封装成对象存储到第一步实例化的Promise对象的callbacks属性上。

但是我们对回调函数的封装可就不能像原来一样了,我们定义一个函数,在这个函数中执行回调,那么这个回调被执行的结果就可以决定then方法返回的Promise对象的状态和结果。

那么我们接下来就要通过这个回调的执行结果来修改then方法要返回的Promise对象的状态。那么我们是不是也要判断回调返回值的类型?如果返回的不是Promise对象,那就把then返回的Promise对象状态改为成功。我们来看一下结果:

image-20220316102121307

image-20220316102235185我们看见现在我们回调现在返回的都不是Promise对象,输出结果也都是没有问题的,那么如果回调函数返回的是一个Promise对象的话呢?那和同步任务是不是也类似?既然回调返回的是Promise对象,那么就可以调用then方法,那么我们根据then方法来进行相关的处理就可以了,包括回调函数抛出异常也是和同步任务的处理一样,大家尝试自己来补全代码,都是同一个原理,这里就不再赘述了

以上我们便实现了异步任务的then方法返回一个新的Promise对象。

可能大家在写完之后会发现我们好像写了好多重复代码啊,我希望大家能有自己优化代码的能力,我最后将会我的完整代码放在我的git仓里,大家有需要的可以来参考,我这里就不贴代码了。

catch方法以及异常穿透

我们现在基本算是已经实现了then方法了,但是我们还有一个很重要的功能,就是异常穿透。因为我们then方法是要进行链式调用的啊,如果调用链中间某一环出现了异常我们没有异常穿透的话在每一环都要catch一下才行,那么我们异常穿透要怎么实现呢?首先肯定要实现catch功能,那么我们现在如果在then方法后面调用catch的话会怎么样呢?

let p = new Promise((resolve, reject) => {
  setTimeout(() => reject("error"),1000);
});
p.then(
  value => console.log(111)
).then(
  value => console.log(222)
).catch(
  reason => console.warn(reason)
);

我们先这样实例化一个Promise对象,并且让Promise对象状态为失败,而我们链式调用then方法,而且只指定成功时的回调,我们来看一下结果是什么样子,按照预期的话应该会被catch方法捕获:

image-20220316105858153

报错了,告诉我们catch不是一个函数,为什么呢?因为我们根本都没有给Promise来添加一个catch方法啊,所以这里肯定是会报错的,那么我们就把这个catch方法给加上:

Promise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected);
}

我们之前在介绍catch方法的时候就说过,catch是把then方法做了一个独立封装,而且catch只接收一个函数类型的参数,并且会返回一个失败状态的Promise对象,那么我们就直接拿then方法来封装就好了,我们来看一下结果:

image-20220316111417123

现在不报错了,但是我们的输出结果好像不太对劲。我们应该输出error才对啊,这是为什么呢?我们来分析一下,我们Promise对象里面开的是异步任务对不对?那么调用then的时候是不是状态还没改变?然后就把我们指定的回调都保存到实例对象上了?但是我们是不是根本没有指定失败时的回调啊?那么当我们这个Promise的异步任务执行完成之后,把Promise的状态修改成了失败,那么肯定要去调用失败时的回调,但是我们没有指定失败时的回调,使用就输出了这么个问题。

但是Promise是允许我们在链式调用中只指定一个回调另一个回调不传的,但是不传不代表Promise内部底层没有,不然的话我们传undefined进去也肯定会报错的,那么我们是不是也应该在then方法中来做一个相应的处理来解决这个问题呢?

Promise.prototype.then = function (onResolved, onRejected) {
  if (typeof onRejected !== "function") {
    onRejected = reason => { throw reason; };
  }
  if (typeof onResolved !== "function") {
    onResolved = value => value;
  }
  return new Promise((resolve, reject) => {...});
};

我们来看这段代码,我们判断了一下onRejectedonResolved这两个形参的类型,如果是函数那就继续,如果不是函数,那么我们就来指定一个默认函数,onRejected指定的默认函数大家应该都能明白,如果onRejected传入进来不是函数,那么通常可能代表着我们没有传这个参数,那么我们如果异步任务是失败的,但是我们却没有传这个回调,那么我们就抛出一个异常让catch去捕获。

但是onResolved指定的默认函数是什么意思呢?这个是Promise的一个值传递,比如我这个Promise对象是成功的,但是我在调用then的时候并没有指定成功时的回调函数,那么就将通过这个默认函数来传递value值供then方法来返回一个新的Promise对象来进行接下来的链式调用。

那么我们现在来看一下失败时会怎么样:

image-20220316113007444

现在catch方法成功被调用并输出了我们预期的结果。那么我们来测一下成功时的值传递:

let p = new Promise((resolve, reject) => {
  setTimeout(() => resolve("OK"),1000);
});
p.then(

).then(
  value => console.log(222)
).catch(
  reason => console.warn(reason)
);

这次我们在then方法调用链的第一环并没有指定任何回调,来看一下结果:

image-20220316113226465

成进行了后面的链式调用并输出了相应结果。以上便是我们对catch方法以及异常穿透的实现。

resolvereject函数的封装

看到这个标题大家可能会很奇怪,resolvereject函数不是早就封装好了吗?这里的resolvereject函数和我们之前说的不是一回事,之前的是Promise函数里的内置函数,这里是指PromiseAPI中的Promise.resolvePromise.reject。那么我们首先先看一下我们目前直接调这两个方法会是什么结果:

image-20220316130629408

image-20220316130702717

报错了说resolvereject不是一个函数,为什么呢?因为我们没有给Promise添加resolvereject方法,那么我们现在来把这两个方法添加上:

Promise.resolve = function(value){

}

Promise.reject = function(reason){

}

我们要注意一点,我们在给Promise添加resolvereject方法时要明确一点就是这两个方法是Promise函数对象的,而不是Promise实例对象的,所以我们不能用Promise.prototype,好了现在我们有了这两个方法了,我们来回忆一下这两个方法是用来干什么的。

  • Promise.resolve将返回一个成功或者失败的新的Promise对象
  • 如果传入的参数不是Promise对象,则返回一个成功的Promise对象,且结果值是我们传入的value
  • 如果传入的参数是一个Promise对象,则返回一个状态和结果值都与传入的Promise对象相同的新的Promise对象
  • Promise.reject将返回一个失败的新的Promise对象,且返回的Promise对象的结果值就是我们传入的值

那么我们应该这么实现我们这两个方法的内部逻辑呢?我们来看一下代码:

Promise.resolve = function (value) {
  return new Promise((resolve, reject) => {
    if (value instanceof Promise) {
      value.then(
        v => resolve(v),
        r => reject(r)
      );
    } else {
      resolve(value);
    }
  });
}

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

首先来看两个函数的最外层的操作,我们都return一个新的Promise对象,先来看resolve,我们传入了value,有两种情况,Promise对象,或者不是Promise对象,那么我们就要判断一下,如果不是Promise对象,就直接调resolve函数修改状态,如果是Promise对象,那就调用then方法在回调里面修改状态

然后我们来看reject函数,这个就简单了,因为reject函数只会返回一个失败的Promise而且我们传什么,结果值就是什么,那么直接调用reject来改状态就好了。

let p1 = Promise.resolve("OK");
let p2 = Promise.resolve(new Promise((resolve, reject) => reject("OH NO")));
let p3 = Promise.reject("Error");
let p4 = Promise.reject(new Promise((resolve, reject) => reject("F**K")));
console.log(p1);
console.log(p2);
console.log(p3);
console.log(p4);

我们现在用这两个方法来生成了 4 个Promise对象,然后输出到控制台上我们来看一下结果:

image-20220316133628837

我们看到我们控制台中输出了相应的结果也是完全符合Promise规则的。

以上便是resolvereject函数的封装。

all方法的封装

前面我们实现了thencatchresolvereject以及多个核心功能,其实到这自定义封装距离结束已经不远了,接下来呢我们来介绍一下all方法的封装。

首先我们来回忆一下all方法是干什么的。这个方法也是Promise函数对象自身的一个方法,接收一个Promise实例对象的数组,并返回一个新的Promise对象,如果数组中所有Promise对象都是成功的,那么返回的新的Promise就是成功的,而且结果值是数组中所有Promise对象的结果值组成的数组。如果数组中有失败的Promise对象,那么返回的Promise对象的状态就是失败的,而结果值则是失败的那个Promise对象的结果值。

那么我们就不做测试了,我们现在还没有给Promise函数添加all方法,直接测试肯定报错,我们先来添加方法吧。

Promise.all = function (promises) {
  return new Promise((resolve, reject) => {

  });
}

我们来看一下,这样我们就实现了all方法的一个基本结构,但是这样的话肯定不符合我们的需求的,首先我们接收的形参是一个数组,而且只有当数组中的Promise对象都是成功的时候才能把我们返回的Promise对象状态修改为成功。那么我们怎么判断数组中的Promise对象是不是都是成功的?那么是不是要for循环?

Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(
        value => { },
        reason => reject(reason)
      );
    }
  });
}

我们来看这段代码,我们遍历整个数组,这个数组里面所有的元素都是Promise对象,那么只要是Promise对象那么就可以调用then方法,然后我们来指定回调,成功的回调函数我现在还没有实现,我们先来看失败的回调,all方法的逻辑是什么?只有数组中有任何一个失败的Promise对象,那么就不用再考虑其他的了,直接返回一个失败的Promise对象,而且结果值就是这个失败的Promise对象的结果值,那么我们是不是直接调用reject函数来修改状态就行了?我们来测试一下:

let p1 = Promise.resolve("OK");
let p2 = Promise.reject("Error");
let p3 = Promise.resolve("Yes");
let result = Promise.all([p1, p2, p3]);
console.log(result);

我们创建了三个Promise对象,其中有一个是失败的,看一下结果:

image-20220316141811318

我们看到控制台输出的是一个失败的Promise对象,而且结果值就是失败的那个Promise对象的结果值,那么如果三个都是成功的应该这么实现呢?

Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    let count = 0;
    let result = [];
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(
        value => {
          count++;
          result[i] = value;
          if (count === promises.length) resolve(result);
        },
        reason => reject(reason)
      );
    }
  });
}

我们这次来看这段代码,我们在for循环中肯定是不能直接执行resolve函数的,因为我们要等到确定所有的Promise对象都是成功的才能执行resolve函数,所以我们预先声明一个变量,每当成功的回调被执行都让它自增,等到这个变量和数组长度相等的时候那是不是就代表着整个数组里面都是成功的Promise,那么我们就可以执行resolve函数了。

但是我们现在可以修改状态了,但是结果值呢?我们说了如果全是成功,返回的结果值是这些数组里所有Promise对象的结果值组成的数组。那么我们就要预先声明一个数组用于存放结果值,但是我们这里为什么没有用push方法向数组里面添加结果呢?

因为结果值数组的顺序要和promises数组顺序一致,这样的话就可以保证不会因为异步任务完成的时间不同而导致顺序错乱,那么我们 这次用三个成功的Promise对象来测一下:

image-20220316142956284

我们看见这次输出的Promise对象是一个成功的,而且结果值也是按照之前顺序的一个数组。以上我们便完成了对all方法的封装。

race方法的封装

接下来我们来实现最后一个APIrace方法和all方法很像,但是race方法不用像all方法那样来确定数组中每个Promise对象的状态,这是一个数组中的Promise对象赛跑的机制,谁最先改变状态,谁的状态和结果值就是race方法返回的Promise的状态和结果值,那么就简单了,我们先来添加方法:

Promise.all = function (promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(
        value => resolve(value),
        reason => reject(reason)
      );
    }
  });
}

我们来看一下代码,可能有人要问,这次我们为什么不计数了呢?因为用不着了,我们这里的返回值状态取决于第一个改变状态的Promise对象,所以说直接改就行了那么我们来测一下:

let p1 = new Promise((resolve, reject) => setTimeout(() => reject("Error"), 1000));
let p2 = Promise.resolve("It's OK");
let p3 = Promise.reject("OH NO");
let result = Promise.all([p1, p2, p3]);
console.log(result);

我们这次让第一个Promise对象封装一个异步任务,那么我们来分析一下哪个Promise对象最先改变状态,首先肯定不是p1对吧,因为p1开了异步任务,要等 1 秒才能修改状态,那么来到p2,这是个同步的,直接就修改了状态,然后才执行p3所以说结果输出的应该是一个成功的Promise对象,结果值和p2的结果值一致:

image-20220316144742680

如此一来我们便实现了Promise中所有的API

then回调函数异步执行

我接下来来实现一个细节上的东西。我们先来看Promise的一个细节:

let p = new Promise((resolve,reject)=>{
  resolve("OK");
  console.log(111);
});
p.then(v=>console.log(222));
console.log(333);

我们来看一下Promise的结果是什么样子:

image-20220316145655643

我们看控制台上输出的内容好像和我想的不一样啊,因为Promise在设计的时候是吧then中的回调异步执行的,那我们来看一下我们自己手写的Promise

image-20220316145829828

我们自己写的好像和Promise的设计不符合啊,那么我们用setTimeout函数来把我们回调调用部分包裹起来是不是就实现异步了?代码我这里就不贴了,大家自己尝试实现一下。

理论上我们接下来要介绍一下怎么把我们的Promise封装成一个类,因为到现在为止我们都是函数式编程,但是我觉得大家可以自己尝试把函数式编程封装成类,我们这里就不赘述了。

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/lesson07_encapsulation_of_promise2/