专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序员的那些事  ·  OpenAI ... ·  2 天前  
程序员的那些事  ·  印度把 DeepSeek ... ·  3 天前  
程序员小灰  ·  清华大学《DeepSeek学习手册》(全5册) ·  3 天前  
程序员小灰  ·  3个令人惊艳的DeepSeek项目,诞生了! ·  3 天前  
OSC开源社区  ·  升级到Svelte ... ·  5 天前  
51好读  ›  专栏  ›  SegmentFault思否

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

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

正文

本文写给有一定Promise使用经验的人,如果你还没有使用过Promise,这篇文章可能不适合你,建议先了解Promise的使用

Promise标准解读

1、只有一个then方法,没有catch,race,all等方法,甚至没有构造函数

Promise标准中仅指定了Promise对象的then方法的行为,其它一切我们常见的方法/函数都并没有指定,包括catch,race,all等常用方法,甚至也没有指定该如何构造出一个Promise对象,另外then也没有一般实现中(Q, $q等)所支持的第三个参数,一般称onProgress

2、then方法返回一个新的Promise

Promise的then方法返回一个新的Promise,而不是返回this,此处在下文会有更多解释

  1. promise2 = promise1.then(alert)

  2. promise2 != promise1 // true

3、不同Promise的实现需要可以相互调用(interoperable)

4、Promise的初始状态为pending,它可以由此状态转换为fulfilled(本文为了一致把此状态叫做resolved)或者rejected,一旦状态确定,就不可以再次转换为其它状态,状态确定的过程称为settle

5、更具体的标准见这里:https://promisesaplus.com/

一步一步实现一个Promise

下面我们就来一步一步实现一个Promise

构造函数

因为标准并没有指定如何构造一个Promise对象,所以我们同样以目前一般Promise实现中通用的方法来构造一个Promise对象,也是ES6原生Promise里所使用的方式,即:

  1. // Promise构造函数接收一个executor函数,executor函数执行完同步或异步操作后,调用它的两个参数resolve和reject

  2. var promise = new Promise(function(resolve, reject) {

  3.  /*

  4.    如果操作成功,调用resolve并传入value

  5.    如果操作失败,调用reject并传入reason

  6.  */

  7. })

我们先实现构造函数的框架如下:

  1. function Promise(executor) {

  2.  var self = this

  3.  self.status = 'pending' // Promise当前的状态

  4.  self.data = undefined  // Promise的值

  5.  self.onResolvedCallback = [] // Promise resolve时的回调函数集,因为在Promise结束之前有可能有多个回调添加到它上面

  6.   self.onRejectedCallback = [] // Promise reject时的回调函数集,因为在Promise结束之前有可能有多个回调添加到它上面

  7.  executor(resolve, reject) // 执行executor并传入相应的参数

  8. }

上面的代码基本实现了Promise构造函数的主体,但目前还有两个问题:

1、我们给executor函数传了两个参数:resolve和reject,这两个参数目前还没有定义

2、executor有可能会出错(throw),类似下面这样,而如果executor出错,Promise应该被其throw出的值reject:

  1. new Promise(function(resolve, reject) {

  2.  throw 2

  3. })

所以我们需要在构造函数里定义resolve和reject这两个函数:

  1. function Promise(executor) {

  2.  var self = this

  3.  self.status = 'pending' // Promise当前的状态

  4.  self.data = undefined  // Promise的值

  5.  self.onResolvedCallback = [] // Promise resolve时的回调函数集,因为在Promise结束之前有可能有多个回调添加到它上面

  6.   self.onRejectedCallback = [] // Promise reject时的回调函数集,因为在Promise结束之前有可能有多个回调添加到它上面

  7.  function resolve(value) {

  8.    // TODO

  9.  }

  10.  function reject(reason) {

  11.    // TODO

  12.  }

  13.  try { // 考虑到执行executor的过程中有可能出错,所以我们用try/catch块给包起来,并且在出错后以catch到的值reject掉这个Promise

  14.    executor(resolve, reject) // 执行executor

  15.  } catch(e) {

  16.    reject(e)

  17.  }

  18. }

有人可能会问,resolve和reject这两个函数能不能不定义在构造函数里呢?考虑到我们在executor函数里是以resolve(value),reject(reason)的形式调用的这两个函数,而不是以resolve.call(promise, value),reject.call(promise, reason)这种形式调用的,所以这两个函数在调用时的内部也必然有一个隐含的this,也就是说,要么这两个函数是经过bind后传给了executor,要么它们定义在构造函数的内部,使用self来访问所属的Promise对象。所以如果我们想把这两个函数定义在构造函数的外部,确实是可以这么写的:

  1. function resolve() {

  2.  // TODO

  3. }

  4. function reject() {

  5.  // TODO

  6. }

  7. function Promise(executor) {

  8.  try {

  9.    executor(resolve.bind(this), reject.bind(this))

  10.  } catch(e) {

  11.    reject.bind(this)(e)

  12.  }

  13. }

但是众所周知,bind也会返回一个新的函数,这么一来还是相当于每个Promise对象都有一对属于自己的resolve和reject函数,就跟写在构造函数内部没什么区别了,所以我们就直接把这两个函数定义在构造函数里面了。不过话说回来,如果浏览器对bind的所优化,使用后一种形式应该可以提升一下内存使用效率。

另外我们这里的实现并没有考虑隐藏this上的变量,这使得这个Promise的状态可以在executor函数外部被改变,在一个靠谱的实现里,构造出的Promise对象的状态和最终结果应当是无法从外部更改的。

接下来,我们实现resolve和reject这两个函数

  1. function Promise(executor) {

  2.  // ...

  3.  function resolve(value) {

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

  5.      self.status = 'resolved'

  6.      self.data = value

  7.      for(var i = 0; i < self.onResolvedCallback.length; i++) {

  8.         self.onResolvedCallback[i](value)

  9.      }

  10.    }

  11.  }

  12.  function reject(reason) {

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

  14.      self.status = 'rejected'

  15.       self.data = reason

  16.      for(var i = 0; i < self.onRejectedCallback.length; i++) {

  17.        self.onRejectedCallback[i](reason)

  18.      }

  19.    }

  20.  }

  21.  // ...

  22. }

基本上就是在判断状态为pending之后把状态改为相应的值,并把对应的value和reason存在self的data属性上面,之后执行相应的回调函数,逻辑很简单,这里就不多解释了。

then方法

Promise对象有一个then方法,用来注册在这个Promise状态确定后的回调,很明显,then方法需要写在原型链上。then方法会返回一个Promise,关于这一点,Promise/A+标准并没有要求返回的这个Promise是一个新的对象,但在Promise/A标准中,明确规定了then要返回一个新的对象,目前的Promise实现中then几乎都是返回一个新的Promise(详情)对象,所以在我们的实现中,也让then返回一个新的Promise对象。

关于这一点,我认为标准中是有一点矛盾的:

标准中说,如果promise2 = promise1.then(onResolved, onRejected)里的onResolved/onRejected返回一个Promise,则promise2直接取这个Promise的状态和值为己用,但考虑如下代码:

  1. promise2 = promise1.then(function foo(value) {

  2.   return Promise.reject(3)

  3. })

此处如果foo运行了,则promise1的状态必然已经确定且为resolved,如果then返回了this(即promise2 === promise1),说明promise2和promise1是同一个对象,而此时promise1/2的状态已经确定,没有办法再取Promise.reject(3)的状态和结果为己用,因为Promise的状态确定后就不可再转换为其它状态。

另外每个Promise对象都可以在其上多次调用then方法,而每次调用then返回的Promise的状态取决于那一次调用then时传入参数的返回值,所以then不能返回this,因为then每次返回的Promise的结果都有可能不同。

下面我们来实现then方法:

  1. // then方法接收两个参数,onResolved,onRejected,分别为Promise成功或失败后的回调

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

  3.   var self = this

  4.  var promise2

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

  6.  onResolved = typeof onResolved === 'function' ? onResolved : function(v) {}

  7.  onRejected = typeof onRejected === 'function' ? onRejected : function(r) {}

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

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

  10.    })

  11.  }

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

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

  14.    })

  15.  }

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

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

  18.    })

  19.  }

  20. }

Promise总共有三种可能的状态,我们分三个if块来处理,在里面分别都返回一个new Promise。

根据标准,我们知道,对于如下代码,promise2的值取决于then里面函数的返回值:

  1. promise2 = promise1.then(function(value) {

  2.  return 4

  3. }, function(reason) {

  4.  throw new Error('sth went wrong')

  5. })

如果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.  })

所以如果想要把then的实参留空且让值可以穿透到后面,意味着then的两个参数的默认值分别为function(value) {return value},function(reason) {throw reason}。 所以我们只需要把then里判断onResolved和onRejected的部分改成如下即可:

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

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

于是Promise神奇的值的穿透也没有那么黑魔法,只不过是then默认参数就是把值往后传或者抛

不同Promise的交互

关于不同Promise间的交互,其实标准里是有说明的,其中详细指定了如何通过then的实参返回的值来决定promise2的状态,我们只需要按照标准把标准的内容转成代码即可。

这里简单解释一下标准:

即我们要把onResolved/onRejected的返回值,x,当成一个可能是Promise的对象,也即标准里所说的thenable,并以最保险的方式调用x上的then方法,如果大家都按照标准实现,那么不同的Promise之间就可以交互了。而标准为了保险起见,即使x返回了一个带有then属性但并不遵循Promise标准的对象(比如说这个x把它then里的两个参数都调用了,同步或者异步调用(PS,原则上then的两个参数需要异步调用,下文会讲到),或者是出错后又调用了它们,或者then根本不是一个函数),也能尽可能正确处理。

关于为何需要不同的Promise实现能够相互交互,我想原因应该是显然的,Promise并不是JS一早就有的标准,不同第三方的实现之间是并不相互知晓的,如果你使用的某一个库中封装了一个Promise实现,想象一下如果它不能跟你自己使用的Promise实现交互的场景。。。

建议各位对照着标准阅读以下代码,因为标准对此说明的非常详细,所以你应该能够在任意一个Promise实现中找到类似的代码:

  1. /*

  2. resolvePromise函数即为根据x的值来决定promise2的状态的函数

  3. 也即标准中的[Promise Resolution Procedure](https://promisesaplus.com/#point-47)

  4. x为`promise2 = promise1.then(onResolved, onRejected)`里`onResolved/onRejected`的返回值

  5. `resolve`和`reject`实际上是`promise2`的`executor`的两个实参,因为很难挂在其它的地方,所以一并传进来。

  6. 相信各位一定可以对照标准把标准转换成代码,这里就只标出代码在标准中对应的位置,只在必要的地方做一些解释

  7. */

  8. function resolvePromise(promise2, x, resolve, reject) {

  9.  var then

  10.   var thenCalledOrThrow = false

  11.  if (promise2 === x) { // 对应标准2.3.1节

  12.     return reject(new TypeError('Chaining cycle detected for promise!'))

  13.  }

  14.   if (x instanceof Promise) { // 对应标准2.3.2节

  15.    // 如果x的状态还没有确定,那么它是有可能被一个thenable决定最终状态和值的

  16.    // 所以这里需要做一下处理,而不能一概的以为它会被一个“正常”的值resolve

  17.    if (x.status === 'pending') {

  18.      x.then(function(value) {

  19.        resolvePromise(promise2, value, resolve, reject)

  20.      }, reject)

  21.    } else { // 但如果这个Promise的状态已经确定了,那么它肯定有一个“正常”的值,而不是一个thenable,所以这里直接取它的状态

  22.      x. then(resolve, reject)

  23.    }

  24.    return

  25.  }

  26.  if ((x !== null) && ((typeof x === 'object' ) || (typeof x === 'function'))) { // 2.3.3

  27.    try {

  28.       // 2.3.3.1 因为x.then有可能是一个getter,这种情况下多次读取就有可能产生副作用

  29.      // 即要判断它的类型,又要调用它,这就是两次读取

  30.      then = x.then

  31.       if (typeof then === 'function') { // 2.3.3.3

  32.        then.call(x, function rs(y) { // 2.3.3.3.1

  33.           if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准

  34.          thenCalledOrThrow = true

  35.           return resolvePromise(promise2, y, resolve, reject) // 2.3.3.3.1

  36.        }, function rj(r) { // 2.3.3.3.2

  37.          if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准

  38.          thenCalledOrThrow = true

  39.          return reject(r)

  40.        })

  41.      } else { // 2.3.3.4

  42.        resolve(x)

  43.      }

  44.    } catch (e) { // 2.3.3.2

  45.      if (thenCalledOrThrow) return // 2.3.3.3.3 即这三处谁选执行就以谁的结果为准

  46.      thenCalledOrThrow = true

  47.      return reject(e)

  48.    }

  49.  } else { // 2.3.4

  50.    resolve(x)

  51.  }

  52. }

然后我们使用这个函数的调用替换then里几处判断x是否为Promise对象的位置即可,见下方完整代码。

最后,我们刚刚说到,原则上,promise.then(onResolved, onRejected)里的这两相函数需要异步调用,关于这一点,标准里也有说明:

In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack.

所以我们需要对我们的代码做一点变动,即在四个地方加上setTimeout(fn, 0),这点会在完整的代码中注释,请各位自行发现。

事实上,即使你不参照标准,最终你在自测试时也会发现如果then的参数不以异步的方式调用,有些情况下Promise会不按预期的方式行为,通过不断的自测,最终你必然会让then的参数异步执行,让executor函数立即执行。本人在一开始实现Promise时就没有参照标准,而是自己凭经验测试,最终发现的这个问题。

至此,我们就实现了一个的Promise,完整代码如下:

  1. try {

  2.  module.exports = Promise

  3. } catch (e) {}

  4. function Promise(executor) {

  5.  var self = this

  6.   self.status = 'pending'

  7.  self.onResolvedCallback = []

  8.   self.onRejectedCallback = []

  9.   function resolve(value) {

  10.    if (value instanceof Promise) {

  11.      return value.then(resolve, reject)

  12.    }

  13.    setTimeout(function() { // 异步执行所有的回调函数

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

  15.        self.status = 'resolved'

  16.         self.data = value

  17.        for (var i = 0; i < self.onResolvedCallback.length; i++) {

  18.           self.onResolvedCallback[i](value)

  19.        }

  20.      }

  21.    })

  22.  }

  23.  function reject(reason) {

  24.    setTimeout( function() { // 异步执行所有的回调函数

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

  26.        self .status = 'rejected'

  27.        self.data = reason

  28.        for (var i = 0; i < self.onRejectedCallback.length; i++) {

  29.           self.onRejectedCallback[i](reason)

  30.        }

  31.      }

  32.    })

  33.  }

  34.   try {

  35.    executor(resolve, reject)

  36.  } catch (reason) {

  37.    reject(reason)

  38.  }

  39. }

  40. function resolvePromise(promise2, x, resolve, reject) {

  41.  var then

  42.   var thenCalledOrThrow = false

  43.   if (promise2 === x) {

  44.    return reject(new TypeError('Chaining cycle detected for promise!'))

  45.  }

  46.   if (x instanceof Promise) {

  47.    if (x.status === 'pending') { //because x could resolved by a Promise Object

  48.      x. then(function(v) {

  49.        resolvePromise(promise2, v, resolve, reject)

  50.      }, reject)

  51.    } else { //but if it is resolved, it will never resolved by a Promise Object but a static value;

  52.      x. then(resolve, reject)

  53.    }

  54.     return

  55.  }

  56.  if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) {

  57.     try {

  58.      then = x.then //because x.then could be a getter

  59.       if (typeof then === 'function') {

  60.        then.call(x, function rs(y) {

  61.           if (thenCalledOrThrow) return

  62.          thenCalledOrThrow = true

  63.          return resolvePromise(promise2, y, resolve, reject)

  64.        }, function rj(r) {

  65.          if (thenCalledOrThrow) return

  66.          thenCalledOrThrow = true

  67.          return reject(r)

  68.        })

  69.      } else {

  70.        resolve(x)

  71.      }

  72.    } catch (e) {

  73.      if (thenCalledOrThrow) return

  74.      thenCalledOrThrow = true

  75.      return reject(e)

  76.    }

  77.  } else {

  78.    resolve(x)

  79.  }

  80. }

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

  82.  var self = this

  83.   var promise2

  84.  onResolved = typeof onResolved === 'function' ? onResolved : function(v) {

  85.    return v

  86.  }

  87.  onRejected = typeof onRejected === 'function' ? onRejected : function(r) {

  88.     throw r

  89.  }

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

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

  92.      setTimeout(function() { // 异步执行onResolved

  93.         try {

  94.           var x = onResolved(self.data)

  95.          resolvePromise(promise2, x, resolve, reject)

  96.        } catch (reason) {

  97.          reject(reason)

  98.        }

  99.      })

  100.    })

  101.  }

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

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

  104.      setTimeout( function() { // 异步执行onRejected

  105.        try {

  106.           var x = onRejected(self.data)

  107.          resolvePromise(promise2, x, resolve, reject)

  108.        } catch (reason) {

  109.          reject(reason)

  110.        }

  111.      })

  112.    })

  113.  }

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

  115.    // 这里之所以没有异步执行,是因为这些函数必然会被resolve或reject调用,而resolve或reject函数里的内容已是异步执行,构造函数里的定义

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

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

  118.        try {

  119.           var x = onResolved(value)

  120.          resolvePromise(promise2, x, resolve, reject)

  121.        } catch (r) {

  122.          reject(r)

  123.        }

  124.      })

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

  126.          try {

  127.             var x = onRejected(reason)

  128.            resolvePromise(promise2, x, resolve, reject)

  129.          } catch (r) {

  130.            reject(r)

  131.          }

  132.        })

  133.    })

  134.  }

  135. }

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

  137.  return this.then(null, onRejected)

  138. }

  139. Promise.deferred = Promise







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