Promise/A + specification

Promise/A+ is A standard specification about JS Promise, ES6 Promise is actually A superset of this specification, understand this specification can help you better understand ES6 Promise

The original specification

My Chinese-English translation

The implementation code

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

function PromiseDLL(fn) {
  this.state = PENDING
  this.value = null
  this.reason = null
  this.onFulfilled = null
  this.onRejected = null
  try {
    fn(this.resolve, this.reject)
  } catch (err) {
    this.reject(err)
  }
}

PromiseDLL.prototype.resolve = function (value) {
  if (this.state ! == PENDING) {return
  }
  this.onFulfilled && this.onFulfilled(this.value)
  this.value = value
  this.state = FULFILLED
}

PromiseDLL.prototype.reject = function (reason) {
  if (this.state ! == PENDING) {return
  }
  this.onRejected && this.onRejected(this.value)
  this.reason = reason
  this.state = REJECTED
}

PromiseDLL.prototype.then = function (onFulfilled, onRejected) {
  const that = this
  return new Promise((resolve, reject) = > {
    function resolveP(x) {
      if (x === this) {
        throw TypeError('cannot be same object')}else {
        const then = x.then
        if ((typeof x === 'object' || typeof x === 'function') && typeof then === 'function') {
          then.call(x, resolve, reject)
        } else {
          resolve(x)
        }
      }
    }

    function fulfillHandler(value) {
      if (typeof onFulfilled === 'function') {
        resolveP(onFulfilled(value))
      } else {
        resolve(value)
      }
    }
    function rejectHandler(reason) {
      if (typeof onRejected === 'function') {
        resolveP(onRejected(reason))
      } else {
        reject(reason)
      }
    }
    switch (this.state) {
      case PENDING:
        that.onFulfilled = fulfillHandler
        that.onRejected = rejectHandler
        break
      case FULFILLED:
        setTimeout(() = > {
          fulfillHandler(that.value)
        }, 0)
        break
      case REJECTED:
        setTimeout(() = > {
          rejectHandler(this.reason)
        }, 0)
        break
      default:
        throw TypeError('undefined promise state')}}}Copy the code

Some Bulls**t

I am more progress in the implementation of the process, the test case also again all after (secretly happy), probably because of just A few days ago already in the process of translation and bilingual writing reading through A number of times the original Promise/A + specification, but only to put an article code is A little dry, or say A jaw rabbah satisfied, So here are some thoughts on the implementation:

  • Some of the rules in the specification that are broken down into multiple chapters are actually linked back and forth, such as foronFulfilled/onRejectedThrow error related description, found in the implementation
    try {
      fn(this.resolve, this.reject)
    } catch (err) {
      this.reject(err)
    }
    Copy the code

    This code already covers various throw handling rules, so there is no need to implement it againthen/resolve/rejectMethod to do additional exception handling, which also showsPromise/A+The specification itself is very elegant

  • The Promise/A+ specification is deprecatedpromise2 = promise1.then(...)In thepromise2 ! == promise1Requirements (seeOmissions – 1.3 -), here is the implementationthenMethod thought about returning directlythisTo avoid creating new ones too oftenPromiseExample, but did not continue to think about half, if there is time to think clearly about this part later and then make up
  • thenMethods can be implemented through macro tasks or microtasks (Promise/A+)Note 3.1Explicitly not required here), used heresetTimeoutTo meet theRules 2.2.4, but if you want to implement it based on microtasks, you can consider using other methods (Here I have a hunch that I can write another piece of crap about macro tasks and micro tasks)

Test Promise/A +

The Promise/A+ organization provides an official test case and uses it in A simple way. Here, we use the adapters provided by the Promise/A+ organization to test the adapters. The code is as follows

// Adapter
PromiseDLL.deferred = () = > {
  const res = {}
  res.promise = new Promise((resolve, reject) = > {
    Object.assign(res, { resolve, reject })
  })
  return res
}

module.exports = PromiseDLL
Copy the code
// package.json{..."scripts": {..."test": "promises-aplus-tests promise-aplus". },... }Copy the code

All 872 test cases passed