专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
稀土掘金技术社区  ·  浏览器指纹-探究前端如何识别用户设备 ·  昨天  
OSC开源社区  ·  尤雨溪创业公司VoidZero发布Oxlin ... ·  4 天前  
程序员的那些事  ·  突发!紧急召回 49 万台,罗马仕 3 ... ·  3 天前  
程序猿  ·  有了这些 VS Code 的 ... ·  3 天前  
51好读  ›  专栏  ›  SegmentFault思否

剖析 Promise 内部结,实现一个 Promise 类

SegmentFault思否  · 公众号  · 程序员  · 2017-11-17 08:00

正文

请到「今天看啥」查看全文


(value) {

  • return 4

  • }, function (reason) {

  • throw new Error ( 'sth went wrong' )

  • })

  • 如果promise1被resolve了,promise2的将被4 resolve,如果promise1被reject了,promise2将被new Error('sth went wrong') reject,更多复杂的情况不再详述。

    所以,我们需要在then里面执行onResolved或者onRejected,并根据返回值(标准中记为x)来确定promise2的结果,并且,如果onResolved/onRejected返回的是一个Promise,promise2将直接取这个Promise的结果:

    1. Promise.prototype.then = function(onResolved, onRejected) {

    2.  var self = this

    3.  var promise2

    4.  // 根据标准,如果then的参数不是function,则我们需要忽略它,此处以如下方式处理

    5.  onResolved = typeof onResolved === 'function' ? onResolved : function(value) {}

    6.  onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {}

    7.  if (self.status === 'resolved') {

    8.    // 如果promise1(此处即为this/self)的状态已经确定并且是resolved,我们调用onResolved

    9.    // 因为考虑到有可能throw,所以我们将其包在try/catch块里

    10.    return promise2 = new Promise(function(resolve, reject) {

    11.      try {

    12.        var x = onResolved(self.data)

    13.        if (x instanceof Promise) { // 如果onResolved的返回值是一个Promise对象,直接取它的结果做为promise2的结果

    14.          x.then(resolve, reject)

    15.        }

    16.        resolve(x) // 否则,以它的返回值做为promise2的结果

    17.      } catch (e) {

    18.        reject(e) // 如果出错,以捕获到的错误做为promise2的结果

    19.      }

    20.    })

    21.  }

    22.  // 此处与前一个if块的逻辑几乎相同,区别在于所调用的是onRejected函数,就不再做过多解释

    23.  if (self.status === 'rejected') {

    24.    return promise2 = new Promise(function(resolve, reject) {

    25.      try {

    26.        var x = onRejected(self.data)

    27.        if (x instanceof Promise) {

    28.          x.then(resolve, reject)

    29.        }

    30.      } catch (e) {

    31.        reject(e)

    32.      }

    33.    })

    34.  }

    35.  if (self.status === 'pending') {

    36.  // 如果当前的Promise还处于pending状态,我们并不能确定调用onResolved还是onRejected,

    37.  // 只能等到Promise的状态确定后,才能确实如何处理。

    38.  // 所以我们需要把我们的**两种情况**的处理逻辑做为callback放入promise1(此处即this/self)的回调数组里

    39.  // 逻辑本身跟第一个if块内的几乎一致,此处不做过多解释

    40.    return promise2 = new Promise(function(resolve, reject) {

    41.      self.onResolvedCallback.push(function(value) {

    42.        try {

    43.          var x = onResolved(self.data)

    44.          if (x instanceof Promise) {

    45.            x.then(resolve, reject)

    46.          }

    47.        } catch (e) {

    48.          reject(e)

    49.        }

    50.      })

    51.      self.onRejectedCallback.push(function(reason) {

    52.        try {

    53.          var x = onRejected(self.data)

    54.          if (x instanceof Promise) {

    55.            x.then(resolve, reject)

    56.          }

    57.        } catch (e) {

    58.          reject(e)

    59.        }

    60.      })

    61.    })

    62.  }

    63. }

    64. // 为了下文方便,我们顺便实现一个catch方法

    65. Promise.prototype.catch = function(onRejected) {

    66.  return this.then(null, onRejected)

    67. }

    至此,我们基本实现了Promise标准中所涉及到的内容,但还有几个问题:

    1、不同的Promise实现之间需要无缝的可交互,即Q的Promise,ES6的Promise,和我们实现的Promise之间以及其它的Promise实现,应该并且是有必要无缝相互调用的,比如:

    1. // 此处用MyPromise来代表我们实现的Promise

    2. new MyPromise(function(resolve, reject) { // 我们实现的Promise

    3.  setTimeout(function() {

    4.    resolve(42)

    5.  }, 2000)

    6. }).then(function() {

    7.  return new Promise.reject(2) // ES6的Promise

    8. }).then(function() {

    9.  return Q.all([ // Q的Promise

    10.    new MyPromise(resolve=>resolve(8)), // 我们实现的Promise

    11.    new Promise.resolve(9), // ES6的Promise

    12.    Q.resolve(9) // Q的Promise

    13.  ])

    14. })

    我们前面实现的代码并没有处理这样的逻辑,我们只判断了onResolved/onRejected的返回值是否为我们实现的Promise的实例,并没有做任何其它的判断,所以上面这样的代码目前是没有办法在我们的Promise里正确运行的。

    2、下面这样的代码目前也是没办法处理的:

    1. new Promise(resolve=>resolve(8))

    2.  .then()

    3.  .then()

    4.  .then(function foo(value) {

    5.    alert(value)

    6.  })

    正确的行为应该是alert出8,而如果拿我们的Promise,运行上述代码,将会alert出undefined。这种行为称为穿透,即8这个值会穿透两个then(说Promise更为准确)到达最后一个then里的foo函数里,成为它的实参,最终将会alert出8。

    下面我们首先处理简单的情况,值的穿透

    Promise值的穿透

    通过观察,会发现我们希望下面这段代码

    1. new Promise(resolve=>resolve(8))

    2.  .then()

    3.  .catch()

    4.  .then(function(value) {

    5.    alert(value)

    6.  })

    跟下面这段代码的行为是一样的

    1. new Promise(resolve=>resolve(8))

    2.  .then(function(value){

    3.    return value

    4.  })

    5.  .catch(function(reason){

    6.    throw reason

    7.  })

    8.  .then(function(value) {

    9.    alert(value)

    10.  })







    请到「今天看啥」查看全文