本篇文章次要在于探索 Promise 的实现原理,率领大家一步一步实现一个 Promise , 不对其用法做阐明,如果读者还对Promise的用法不理解,能够查看阮一峰老师的ES6 Promise教程。

接下来,带你一步一步实现一个 Promise

Promise 根本构造


new Promise((resolve, reject) => {  setTimeout(() => {    resolve('FULFILLED')  }, 1000)})
构造函数Promise必须承受一个函数作为参数,咱们称该函数为handlehandle又蕴含resolvereject两个参数,它们是两个函数。

定义一个判断一个变量是否为函数的办法,前面会用到

// 判断变量否为functionconst isFunction = variable => typeof variable === 'function'

首先,咱们定义一个名为 MyPromiseClass,它承受一个函数 handle 作为参数

class MyPromise {  constructor (handle) {    if (!isFunction(handle)) {      throw new Error('MyPromise must accept a function as a parameter')    }  }}

再往下看

Promise 状态和值


Promise 对象存在以下三种状态:

  • Pending(进行中)
  • Fulfilled(已胜利)
  • Rejected(已失败)
状态只能由 Pending 变为 Fulfilled 或由 Pending 变为 Rejected ,且状态扭转之后不会在发生变化,会始终放弃这个状态。

Promise的值是指状态扭转时传递给回调函数的值

上文中handle函数蕴含 resolvereject 两个参数,它们是两个函数,能够用于扭转 Promise 的状态和传入 Promise 的值
new Promise((resolve, reject) => {  setTimeout(() => {    resolve('FULFILLED')  }, 1000)})

这里 resolve 传入的 "FULFILLED" 就是 Promise 的值

resolvereject

  • resolve : 将Promise对象的状态从 Pending(进行中) 变为 Fulfilled(已胜利)
  • reject : 将Promise对象的状态从 Pending(进行中) 变为 Rejected(已失败)
  • resolvereject 都能够传入任意类型的值作为实参,示意 Promise 对象胜利(Fulfilled)和失败(Rejected)的值

理解了 Promise 的状态和值,接下来,咱们为 MyPromise 增加状态属性和值

首先定义三个常量,用于标记Promise对象的三种状态
// 定义Promise的三种状态常量const PENDING = 'PENDING'const FULFILLED = 'FULFILLED'const REJECTED = 'REJECTED'
再为 MyPromise 增加状态和值,并增加状态扭转的执行逻辑
class MyPromise {  constructor (handle) {    if (!isFunction(handle)) {      throw new Error('MyPromise must accept a function as a parameter')    }    // 增加状态    this._status = PENDING    // 增加状态    this._value = undefined    // 执行handle    try {      handle(this._resolve.bind(this), this._reject.bind(this))     } catch (err) {      this._reject(err)    }  }  // 增加resovle时执行的函数  _resolve (val) {    if (this._status !== PENDING) return    this._status = FULFILLED    this._value = val  }  // 增加reject时执行的函数  _reject (err) {     if (this._status !== PENDING) return    this._status = REJECTED    this._value = err  }}

这样就实现了 Promise 状态和值的扭转。上面说一说 Promise 的外围: then 办法

Promisethen 办法


Promise 对象的 then 办法承受两个参数:

promise.then(onFulfilled, onRejected)

参数可选

onFulfilledonRejected 都是可选参数。

  • 如果 onFulfilledonRejected 不是函数,其必须被疏忽

onFulfilled 个性

    如果 onFulfilled 是函数:

  • promise 状态变为胜利时必须被调用,其第一个参数为 promise 胜利状态传入的值( resolve 执行时传入的值)
  • promise 状态扭转前其不可被调用
  • 其调用次数不可超过一次

onRejected 个性

    如果 onRejected 是函数:

  • promise 状态变为失败时必须被调用,其第一个参数为 promise 失败状态传入的值( reject 执行时传入的值)
  • promise 状态扭转前其不可被调用
  • 其调用次数不可超过一次

屡次调用

    then 办法能够被同一个 promise 对象调用屡次

  • promise 胜利状态时,所有 onFulfilled 需依照其注册程序顺次回调
  • promise 失败状态时,所有 onRejected 需依照其注册程序顺次回调

返回

then 办法必须返回一个新的 promise 对象

promise2 = promise1.then(onFulfilled, onRejected);

因而 promise 反对链式调用

promise1.then(onFulfilled1, onRejected1).then(onFulfilled2, onRejected2);

这里波及到 Promise 的执行规定,包含“值的传递”和“谬误捕捉”机制:

1、如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行上面的 Promise 解决过程:[[Resolve]](promise2, x)

  • x 不为 Promise ,则使 x 间接作为新返回的 Promise 对象的值, 即新的onFulfilled 或者 onRejected 函数的参数.
  • xPromise ,这时后一个回调函数,就会期待该 Promise 对象(即 x )的状态发生变化,才会被调用,并且新的 Promise 状态和 x 的状态雷同。

上面的例子用于帮忙了解:

let promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve()  }, 1000)})promise2 = promise1.then(res => {  // 返回一个一般值  return '这里返回一个一般值'})promise2.then(res => {  console.log(res) //1秒后打印出:这里返回一个一般值})
let promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve()  }, 1000)})promise2 = promise1.then(res => {  // 返回一个Promise对象  return new Promise((resolve, reject) => {    setTimeout(() => {     resolve('这里返回一个Promise')    }, 2000)  })})promise2.then(res => {  console.log(res) //3秒后打印出:这里返回一个Promise})

2、如果 onFulfilled 或者onRejected 抛出一个异样 e ,则 promise2 必须变为失败(Rejected),并返回失败的值 e,例如:

let promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('success')  }, 1000)})promise2 = promise1.then(res => {  throw new Error('这里抛出一个异样e')})promise2.then(res => {  console.log(res)}, err => {  console.log(err) //1秒后打印出:这里抛出一个异样e})

3、如果onFulfilled 不是函数且 promise1 状态为胜利(Fulfilled)promise2 必须变为胜利(Fulfilled)并返回 promise1 胜利的值,例如:

let promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('success')  }, 1000)})promise2 = promise1.then('这里的onFulfilled原本是一个函数,但当初不是')promise2.then(res => {  console.log(res) // 1秒后打印出:success}, err => {  console.log(err)})

4、如果 onRejected 不是函数且 promise1 状态为失败(Rejected)promise2必须变为失败(Rejected) 并返回 promise1 失败的值,例如:

let promise1 = new Promise((resolve, reject) => {  setTimeout(() => {    reject('fail')  }, 1000)})promise2 = promise1.then(res => res, '这里的onRejected原本是一个函数,但当初不是')promise2.then(res => {  console.log(res)}, err => {  console.log(err)  // 1秒后打印出:fail})

依据下面的规定,咱们来为 欠缺 MyPromise

批改 constructor : 减少执行队列

因为 then 办法反对屡次调用,咱们能够保护两个数组,将每次 then 办法注册时的回调函数增加到数组中,期待执行

constructor (handle) {  if (!isFunction(handle)) {    throw new Error('MyPromise must accept a function as a parameter')  }  // 增加状态  this._status = PENDING  // 增加状态  this._value = undefined  // 增加胜利回调函数队列  this._fulfilledQueues = []  // 增加失败回调函数队列  this._rejectedQueues = []  // 执行handle  try {    handle(this._resolve.bind(this), this._reject.bind(this))   } catch (err) {    this._reject(err)  }}

增加then办法

首先,then 返回一个新的 Promise 对象,并且须要将回调函数退出到执行队列中

// 增加then办法then (onFulfilled, onRejected) {  const { _value, _status } = this  switch (_status) {    // 当状态为pending时,将then办法回调函数退出执行队列期待执行    case PENDING:      this._fulfilledQueues.push(onFulfilled)      this._rejectedQueues.push(onRejected)      break    // 当状态曾经扭转时,立刻执行对应的回调函数    case FULFILLED:      onFulfilled(_value)      break    case REJECTED:      onRejected(_value)      break  }  // 返回一个新的Promise对象  return new MyPromise((onFulfilledNext, onRejectedNext) => {  })}

那返回的新的 Promise 对象什么时候扭转状态?扭转为哪种状态呢?

依据上文中 then 办法的规定,咱们晓得返回的新的 Promise 对象的状态依赖于以后 then 办法回调函数执行的状况以及返回值,例如 then 的参数是否为一个函数、回调函数执行是否出错、返回值是否为 Promise 对象。

咱们来进一步欠缺 then 办法:

// 增加then办法then (onFulfilled, onRejected) {  const { _value, _status } = this  // 返回一个新的Promise对象  return new MyPromise((onFulfilledNext, onRejectedNext) => {    // 封装一个胜利时执行的函数    let fulfilled = value => {      try {        if (!isFunction(onFulfilled)) {          onFulfilledNext(value)        } else {          let res =  onFulfilled(value);          if (res instanceof MyPromise) {            // 如果以后回调函数返回MyPromise对象,必须期待其状态扭转后在执行下一个回调            res.then(onFulfilledNext, onRejectedNext)          } else {            //否则会将返回后果间接作为参数,传入下一个then的回调函数,并立刻执行下一个then的回调函数            onFulfilledNext(res)          }        }      } catch (err) {        // 如果函数执行出错,新的Promise对象的状态为失败        onRejectedNext(err)      }    }    // 封装一个失败时执行的函数    let rejected = error => {      try {        if (!isFunction(onRejected)) {          onRejectedNext(error)        } else {            let res = onRejected(error);            if (res instanceof MyPromise) {              // 如果以后回调函数返回MyPromise对象,必须期待其状态扭转后在执行下一个回调              res.then(onFulfilledNext, onRejectedNext)            } else {              //否则会将返回后果间接作为参数,传入下一个then的回调函数,并立刻执行下一个then的回调函数              onFulfilledNext(res)            }        }      } catch (err) {        // 如果函数执行出错,新的Promise对象的状态为失败        onRejectedNext(err)      }    }    switch (_status) {      // 当状态为pending时,将then办法回调函数退出执行队列期待执行      case PENDING:        this._fulfilledQueues.push(fulfilled)        this._rejectedQueues.push(rejected)        break      // 当状态曾经扭转时,立刻执行对应的回调函数      case FULFILLED:        fulfilled(_value)        break      case REJECTED:        rejected(_value)        break    }  })}
这一部分可能不太好了解,读者须要联合上文中 then 办法的规定来细细的剖析。

接着批改 _resolve_reject :顺次执行队列中的函数

resolvereject 办法执行时,咱们顺次提取胜利或失败工作队列当中的函数开始执行,并清空队列,从而实现 then 办法的屡次调用,实现的代码如下:

// 增加resovle时执行的函数_resolve (val) {  if (this._status !== PENDING) return  // 顺次执行胜利队列中的函数,并清空队列  const run = () => {    this._status = FULFILLED    this._value = val    let cb;    while (cb = this._fulfilledQueues.shift()) {      cb(val)    }  }  // 为了反对同步的Promise,这里采纳异步调用  setTimeout(() => run(), 0)}// 增加reject时执行的函数_reject (err) {   if (this._status !== PENDING) return  // 顺次执行失败队列中的函数,并清空队列  const run = () => {    this._status = REJECTED    this._value = err    let cb;    while (cb = this._rejectedQueues.shift()) {      cb(err)    }  }  // 为了反对同步的Promise,这里采纳异步调用  setTimeout(run, 0)}

这里还有一种非凡的状况,就是当 resolve 办法传入的参数为一个 Promise 对象时,则该 Promise 对象状态决定以后 Promise 对象的状态。

const p1 = new Promise(function (resolve, reject) {  // ...});const p2 = new Promise(function (resolve, reject) {  // ...  resolve(p1);})

下面代码中,p1p2 都是 Promise 的实例,然而 p2resolve办法将 p1 作为参数,即一个异步操作的后果是返回另一个异步操作。

留神,这时 p1 的状态就会传递给 p2,也就是说,p1 的状态决定了 p2 的状态。如果 p1 的状态是Pending,那么 p2 的回调函数就会期待 p1 的状态扭转;如果 p1 的状态曾经是 Fulfilled 或者 Rejected,那么 p2 的回调函数将会立即执行。

咱们来批改_resolve来反对这样的个性

 // 增加resovle时执行的函数  _resolve (val) {    const run = () => {      if (this._status !== PENDING) return      // 顺次执行胜利队列中的函数,并清空队列      const runFulfilled = (value) => {        let cb;        while (cb = this._fulfilledQueues.shift()) {          cb(value)        }      }      // 顺次执行失败队列中的函数,并清空队列      const runRejected = (error) => {        let cb;        while (cb = this._rejectedQueues.shift()) {          cb(error)        }      }      /* 如果resolve的参数为Promise对象,则必须期待该Promise对象状态扭转后,        以后Promsie的状态才会扭转,且状态取决于参数Promsie对象的状态      */      if (val instanceof MyPromise) {        val.then(value => {          this._value = value          this._status = FULFILLED          runFulfilled(value)        }, err => {          this._value = err          this._status = REJECTED          runRejected(err)        })      } else {        this._value = val        this._status = FULFILLED        runFulfilled(val)      }    }    // 为了反对同步的Promise,这里采纳异步调用    setTimeout(run, 0)  }

这样一个Promise就根本实现了,当初咱们来加一些其它的办法

catch 办法

相当于调用 then 办法, 但只传入 Rejected 状态的回调函数
// 增加catch办法catch (onRejected) {  return this.then(undefined, onRejected)}

动态 resolve 办法

// 增加动态resolve办法static resolve (value) {  // 如果参数是MyPromise实例,间接返回这个实例  if (value instanceof MyPromise) return value  return new MyPromise(resolve => resolve(value))}

动态 reject 办法

// 增加动态reject办法static reject (value) {  return new MyPromise((resolve ,reject) => reject(value))}

动态 all 办法

// 增加动态all办法static all (list) {  return new MyPromise((resolve, reject) => {    /**     * 返回值的汇合     */    let values = []    let count = 0    for (let [i, p] of list.entries()) {      // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve      this.resolve(p).then(res => {        values[i] = res        count++        // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled        if (count === list.length) resolve(values)      }, err => {        // 有一个被rejected时返回的MyPromise状态就变成rejected        reject(err)      })    }  })}

动态 race 办法

// 增加动态race办法static race (list) {  return new MyPromise((resolve, reject) => {    for (let p of list) {      // 只有有一个实例率先扭转状态,新的MyPromise的状态就跟着扭转      this.resolve(p).then(res => {        resolve(res)      }, err => {        reject(err)      })    }  })}

finally 办法

finally 办法用于指定不论 Promise 对象最初状态如何,都会执行的操作
finally (cb) {  return this.then(    value  => MyPromise.resolve(cb()).then(() => value),    reason => MyPromise.resolve(cb()).then(() => { throw reason })  );};

这样一个残缺的 Promsie 就实现了,大家对 Promise 的原理也有理解,能够让咱们在应用Promise的时候更加清晰明了。

残缺代码如下

 // 判断变量否为function  const isFunction = variable => typeof variable === 'function'  // 定义Promise的三种状态常量  const PENDING = 'PENDING'  const FULFILLED = 'FULFILLED'  const REJECTED = 'REJECTED'  class MyPromise {    constructor (handle) {      if (!isFunction(handle)) {        throw new Error('MyPromise must accept a function as a parameter')      }      // 增加状态      this._status = PENDING      // 增加状态      this._value = undefined      // 增加胜利回调函数队列      this._fulfilledQueues = []      // 增加失败回调函数队列      this._rejectedQueues = []      // 执行handle      try {        handle(this._resolve.bind(this), this._reject.bind(this))       } catch (err) {        this._reject(err)      }    }    // 增加resovle时执行的函数    _resolve (val) {      const run = () => {        if (this._status !== PENDING) return        // 顺次执行胜利队列中的函数,并清空队列        const runFulfilled = (value) => {          let cb;          while (cb = this._fulfilledQueues.shift()) {            cb(value)          }        }        // 顺次执行失败队列中的函数,并清空队列        const runRejected = (error) => {          let cb;          while (cb = this._rejectedQueues.shift()) {            cb(error)          }        }        /* 如果resolve的参数为Promise对象,则必须期待该Promise对象状态扭转后,          以后Promsie的状态才会扭转,且状态取决于参数Promsie对象的状态        */        if (val instanceof MyPromise) {          val.then(value => {            this._value = value            this._status = FULFILLED            runFulfilled(value)          }, err => {            this._value = err            this._status = REJECTED            runRejected(err)          })        } else {          this._value = val          this._status = FULFILLED          runFulfilled(val)        }      }      // 为了反对同步的Promise,这里采纳异步调用      setTimeout(run, 0)    }    // 增加reject时执行的函数    _reject (err) {       if (this._status !== PENDING) return      // 顺次执行失败队列中的函数,并清空队列      const run = () => {        this._status = REJECTED        this._value = err        let cb;        while (cb = this._rejectedQueues.shift()) {          cb(err)        }      }      // 为了反对同步的Promise,这里采纳异步调用      setTimeout(run, 0)    }    // 增加then办法    then (onFulfilled, onRejected) {      const { _value, _status } = this      // 返回一个新的Promise对象      return new MyPromise((onFulfilledNext, onRejectedNext) => {        // 封装一个胜利时执行的函数        let fulfilled = value => {          try {            if (!isFunction(onFulfilled)) {              onFulfilledNext(value)            } else {              let res =  onFulfilled(value);              if (res instanceof MyPromise) {                // 如果以后回调函数返回MyPromise对象,必须期待其状态扭转后在执行下一个回调                res.then(onFulfilledNext, onRejectedNext)              } else {                //否则会将返回后果间接作为参数,传入下一个then的回调函数,并立刻执行下一个then的回调函数                onFulfilledNext(res)              }            }          } catch (err) {            // 如果函数执行出错,新的Promise对象的状态为失败            onRejectedNext(err)          }        }        // 封装一个失败时执行的函数        let rejected = error => {          try {            if (!isFunction(onRejected)) {              onRejectedNext(error)            } else {                let res = onRejected(error);                if (res instanceof MyPromise) {                  // 如果以后回调函数返回MyPromise对象,必须期待其状态扭转后在执行下一个回调                  res.then(onFulfilledNext, onRejectedNext)                } else {                  //否则会将返回后果间接作为参数,传入下一个then的回调函数,并立刻执行下一个then的回调函数                  onFulfilledNext(res)                }            }          } catch (err) {            // 如果函数执行出错,新的Promise对象的状态为失败            onRejectedNext(err)          }        }        switch (_status) {          // 当状态为pending时,将then办法回调函数退出执行队列期待执行          case PENDING:            this._fulfilledQueues.push(fulfilled)            this._rejectedQueues.push(rejected)            break          // 当状态曾经扭转时,立刻执行对应的回调函数          case FULFILLED:            fulfilled(_value)            break          case REJECTED:            rejected(_value)            break        }      })    }    // 增加catch办法    catch (onRejected) {      return this.then(undefined, onRejected)    }    // 增加动态resolve办法    static resolve (value) {      // 如果参数是MyPromise实例,间接返回这个实例      if (value instanceof MyPromise) return value      return new MyPromise(resolve => resolve(value))    }    // 增加动态reject办法    static reject (value) {      return new MyPromise((resolve ,reject) => reject(value))    }    // 增加动态all办法    static all (list) {      return new MyPromise((resolve, reject) => {        /**         * 返回值的汇合         */        let values = []        let count = 0        for (let [i, p] of list.entries()) {          // 数组参数如果不是MyPromise实例,先调用MyPromise.resolve          this.resolve(p).then(res => {            values[i] = res            count++            // 所有状态都变成fulfilled时返回的MyPromise状态就变成fulfilled            if (count === list.length) resolve(values)          }, err => {            // 有一个被rejected时返回的MyPromise状态就变成rejected            reject(err)          })        }      })    }    // 增加动态race办法    static race (list) {      return new MyPromise((resolve, reject) => {        for (let p of list) {          // 只有有一个实例率先扭转状态,新的MyPromise的状态就跟着扭转          this.resolve(p).then(res => {            resolve(res)          }, err => {            reject(err)          })        }      })    }    finally (cb) {      return this.then(        value  => MyPromise.resolve(cb()).then(() => value),        reason => MyPromise.resolve(cb()).then(() => { throw reason })      );    }  }