开发中Promise是及其罕用的语法,基本上对于异步的解决大都是通过Promise来进行实现。Promise标准有很多,ES6最终采纳的是Promise/A+ 标准,所以以下代码也根本是基于这个标准来进行编写的。

首先咱们先列举Promise的所有实例办法跟静态方法

实例办法

  • then: new Promise((resolve, reject) => {...}).then(() => {console.log('rsolve胜利回调')}, () => {console.log('reject失败回调')})
  • catch: new Promise((resolve, reject) => {...}).catch(() => {console.log('reject失败办法')})
  • finally: new Promise((resolve, reject) => {...}).finally(() => {console.log('成功失败都进入')})
  • 以上办法调用都将返回新的Promise

静态方法

  • resolve: Promise.resolve(value)返回Promise实例
  • reject: Promise.reject(value)返回Promise实例
  • all: Promise.all(promises): 传入数组格局的Promise并返回新的Promise实例,胜利便依照程序把值返回进去,其中一个失败则间接变成失败
  • race: Promise.race(promises): 传入数组格局的Promise并返回新的Promise实例,胜利与失败取决第一个的实现形式

Promise状态一旦确定变不可再发生变化,有以下三个状态:pendingfulfilledrejected
Promise在浏览器中的实现是放于微工作队列中的,须要做微工作的解决(JavaScript中的Event Loop(事件循环)机制

1.申明Promise的实例办法

class Promise {  _value  _state = 'pending'  _queue = []  constructor(fn) {    if (typeof fn !== 'function') {      throw 'Promise resolver undefined is not a function'    }    /*       new Promise((resolve, reject) => {        resolve: 胜利        reject: 失败      })    */    fn(this._resolve.bind(this), this._reject.bind(this))  }  // 接管1-2参数,第一个为胜利的回调,第二个为失败的回调  then(onFulfilled, onRejected) {    // 有可能曾经resolve了,因为Promise能够提前resolve,而后then办法前面注册    if (this._state === 'fulfilled') {      onFulfilled?.(this._value)      return    }    // reject同理    if (this._state === 'rejected') {      onRejected?.(this._value)      return    }    // Promise还没有实现,push到一个队列,到时候实现的时候,执行这个队列外面对应的函数    this._queue.push({      onFulfilled,      onRejected,    })  }  // 接管失败的回调  catch(onRejected) {    // 相当于间接调用then传入失败的回调    this.then(null, onRejected)  }  // 胜利与失败都执行的回调  finally(onDone) {    const fn = () => onDone()    this.then(fn, fn)  }  // 胜利resolve  _resolve(value) {    // 状态确定了,就不再发生变化了    if (this._state !== 'pending') return    this._state = 'fulfilled'    // 把值存起来,当再次调用的时候间接取这个值就行,因为Promise一旦确定就不会产生扭转了    this._value = value    // 执行后面.then办法外面push函数模式的参数,这样就执行对应的办法了。    this._queue.forEach((callback) => {      callback.onFulfilled?.(this._value)    })  }  // 失败reject  _reject(error) {    // 状态确定了,就不再发生变化了    if (this._state !== 'pending') return    this._state = 'rejected'    this._value = error    this._queue.forEach((callback) => {      callback.onRejected?.(this._value)    })  }}

调用逻辑:

  1. 通过then办法传入函数模式的参数,也就是onFulfilled => then((onFulfilled, onRejected) => {...})
  2. then办法中把onFulfilled函数放入_queue这个汇合中。 => this._queue.push({ onFulfilled, onRejected })
  3. 等异步回调实现,执行resolve函数,这个时候就调用_queue收集好的通过then办法注册的函数。对立执行这些函数,这样就达到异步回调实现,执行对应的then办法外面的函数
// 后果打印const p = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('success')  }, 1000)})p.then((res) => {  console.log(res) // => success})// rejectconst p1 = new Promise((resolve, reject) => {  setTimeout(() => {    reject('fail')  }, 1000)})p1.catch((res) => {  console.log(res) // => fail})// finallyconst p2 = new Promise((resolve, reject) => {  setTimeout(() => {    resolve()  }, 1000)})p2.finally(() => {  console.log('done') // => done})
在线代码演示

2. 微工作解决以及返回Promise

a. 进行微工作解决

在浏览器中 Promise 实现之后会被推入微工作,所以咱们也须要进行这块的解决。浏览器中应用MutationObserver,node能够应用process.nextTick

class Promise {  ...  // 推入微工作  _nextTick(fn) {    if (typeof MutationObserver !== 'undefined') { // 浏览器通过MutationObserver实现微工作的成果      // 这块能够独自拿进去共用,防止不必要的开销,不然每次都须要生成节点。      const observer = new MutationObserver(fn)      let count = 1      const textNode = document.createTextNode(String(count))      observer.observe(textNode, {        characterData: true      })      textNode.data = String(++count)    } else if (typeof process.nextTick !== 'undefined') { // node端通过process.nextTick来实现      process.nextTick(fn)    } else {      setTimeout(fn, 0)    }  }  // 胜利resolve  _resolve(value) {    // 状态确定了,就不再发生变化了    if (this._state !== 'pending') return    // 推入微工作    this._nextTick(() => {      this._state = 'fulfilled'      this._value = value      this._queue.forEach((callback) => {        callback.onFulfilled?.(this._value)      })    })  }  // 失败reject  _reject(error) {    // 状态确定了,就不再发生变化了    if (this._state !== 'pending') return    // 推入微工作    this._nextTick(() => {      this._state = 'rejected'      this._value = error      this._queue.forEach((callback) => {        callback.onRejected?.(this._value)      })    })  }  ...}
成果演示

b. 返回Promise进行链式调用

通常Promise会解决多个异步申请,有时候申请之间是有相互依赖关系的。

例如:

const getUser = () => {  return new Promise((resolve, reject) => {    setTimeout(() => {      resolve({        userId: '123'      })    }, 500)  })}const getDataByUser = (userId) => {  return new Promise((resolve, reject) => {    setTimeout(() => {      // ....      resolve({a: 1})    }, 500)  })}// 应用getUser().then((user) => {  return getDataByUser(user.userId)}).then((res) => {  console.log(res)// {a: 1}})

getDataByUser依赖getUser申请回来的用户信息,这里就须要用到Promise链式的调用,上面咱们来改变咱们的代码

class Promise {  constructor(fn) {    fn(this._resolve.bind(this), this._reject.bind(this))  }  ...  // 1. 这时候then办法须要返回新的Promise了,因为须要进行链式调用,并且下一个then办法承受上一个then办法的值  // 2. 返回的Promise必定是一个新的Promise,不然就会共用状态跟返回后果了。  // 3. 把上一个then办法中的返回值当做下一个Promise resolve的值  then(onFulfilled, onRejected) {    // 返回新的Promise    return new Promise((resolve, reject) => {      // 有可能曾经resolve了,因为Promise能够提前resolve,而后then办法前面注册,这个时候能够间接把值返给函数就好了      if (this._state === 'fulfilled' && onFulfilled) {        this._nextTick(onFulfilled.bind(this, this._value))        return      }      if (this._state === 'rejected' && onRejected) {        this._nextTick(onRejected.bind(this, this._value))        return      }      /*         把以后Promise的then办法的参数跟新的Promise的resolve, reject存到一起,以此来做关联。        这样就能把上一个Promise中的onFulfilled与新的Promise中的resolve两个关联到一块,而后便能够做赋值之类的操作了。reject同理      */      this._queue.push({        onFulfilled,        onRejected,        resolve,        reject      })    })  }  // reject同理  _resolve(value) {    // 状态确定了,就不再发生变化了    if (this._state !== 'pending') return    // 下面示例外面其实返回的是一个Promise,而不是间接返回的值,所以,这里咱们须要做一个非凡解决。    // 就是resolve()的值如果是Promise的对象,咱们须要解析Promise的后果,而后在把值传给resolve    if (typeof value === 'object' && typeof value.then === 'function') {      // 咱们能够把以后_resolve办法传递上来,因为then办法中的参数,一经下个Promise resolve,便会执行then办法对应的参数,而后把对应的值传入。      // 这样就能取到Promise中的值      // this._resove => obj.onFulfilled?.(this._value)      // this._reject => obj.onRejected?.(this._value)      value.then(this._resolve.bind(this), this._reject.bind(this))      return    }    // 推入微工作    this._nextTick(() => {      this._state = 'fulfilled'      this._value = value      this._queue.forEach((obj) => {        // 承受onFulfilled返回值        const val = obj.onFulfilled?.(this._value)        // reoslve这个值,此时 onFulfilled 是以后Promise then办法中的第一个参数: Promise.then((res) => {consolle.log(res)})        // obj.resolve是新的Promise的resolve函数,这样就把then办法中的返回值传给下一个Promise        obj.resolve(val)      })    })  }  ...}
成果演示

调用逻辑:

  1. 微工作采纳MutationObserverprocess.nextTick来进行实现
  2. Promise链式调用,这里通过把then办法中的(onFulfilled, onRejected)参数与新返回的Promise中的(resolve, reject)关联到一起。
  3. 一旦上一个Promise胜利,调用onFulfilled函数,就能够把onFulfilled中返回的值,放到新的Promise的resolve中。
  4. 如果遇到resolve的值是Promise对象,递归进行解析,而后再把值返回进来

残缺代码

class Promise {  _value  _state = 'pending'  _queue = []  constructor(fn) {    if (typeof fn !== 'function') {      throw new Error('Promise resolver undefined is not a function')    }    /*       new Promise((resolve, reject) => {        resolve: 胜利        reject: 失败      })    */    fn(this._resolve.bind(this), this._reject.bind(this))  }  // 接管1-2参数,第一个为胜利的回调,第二个为失败的回调  then(onFulfilled, onRejected) {    // 返回新的Promise    return new Promise((resolve, reject) => {      // 有可能曾经resolve了,因为Promise能够提前resolve,而后then办法前面注册,这个时候能够间接把值返给函数就好了      if (this._state === 'fulfilled' && onFulfilled) {        this._nextTick(onFulfilled.bind(this, this._value))        return      }      if (this._state === 'rejected' && onRejected) {        this._nextTick(onRejected.bind(this, this._value))        return      }      // 把以后Promise的then办法的参数跟新的Promise的resolve, reject存到一起,以此来做关联      this._queue.push({        onFulfilled,        onRejected,        resolve,        reject      })    })  }  // 接管失败的回调  catch(onRejected) {    return this.then(null, onRejected)  }  // 胜利与失败都执行的回调  finally(onDone) {    return this.then((value) => {      onDone()      return value    }, (value) => {      // console.log(value)      onDone()      throw value    })  }  // 推入微工作  _nextTick(fn) {    if (typeof MutationObserver !== 'undefined') { // 浏览器      // 这块能够独自拿进去共用,防止不必要的开销,不然每次都须要生成节点。      const observer = new MutationObserver(fn)      let count = 1      const textNode = document.createTextNode(String(count))      observer.observe(textNode, {        characterData: true      })      textNode.data = String(++count)    } else if (typeof process.nextTick !== 'undefined') { // node      process.nextTick(fn)    } else {      setTimeout(fn, 0)    }  }  // 胜利resolve  _resolve(value) {    // 状态确定了,就不再发生变化了    if (this._state !== 'pending') return    // 下面示例外面其实返回的是一个Promise,而不是间接返回的值,所以,这里咱们须要做一个非凡解决。    // 就是如果resolve()的如果是Promise的对象,咱们须要解析Promise的后果,而后在把值传给resolve    if (typeof value === 'object' && typeof value.then === 'function') {      // 咱们能够把以后_resolve办法传递上来,因为then办法中的参数,一经下个Promise resolve,便会执行then办法对应的参数,而后把对应的值传入。      // 这样就能取到Promise中的值      // this._resove => obj.onFulfilled?.(this._value)      // this._reject => obj.onRejected?.(this._value)      value.then(this._resolve.bind(this), this._reject.bind(this))      return    }    // 推入微工作    this._nextTick(() => {      this._state = 'fulfilled'      this._value = value      this._queue.forEach((obj) => {        // 应用try catch 来捕捉onFulfilled存在函数外部谬误的状况        try {          // 承受onFulfilled返回值,如果不存在,把this._value往下传递          const val = obj.onFulfilled ? obj.onFulfilled(this._value) : this._value          // reoslve这个值,此时 onFulfilled 是以后Promise then办法中的第一个参数: Promise.then((res) => {consolle.log(res)})          // obj.resolve是新的Promise的resolve函数,这样就把then办法中的返回值传给下一个Promise          obj.resolve(val)        } catch (e) {          obj.reject(e)        }      })    })  }  // 失败reject  _reject(error) {    if (this._state !== 'pending') return    this._nextTick(() => {      this._state = 'rejected'      this._value = error      this._queue.forEach((obj) => {        try {          const val = obj.onRejected ? obj.onRejected(this._value) : this._value          // 以后 reject执行结束之后,会返回新的Promise,应该是能失常resolve的,所以这里要用 resolve, 不应该持续应用reject来让下个Promise执行失败流程          obj.resolve(val)        } catch (e) {          obj.reject(e)        }      })    })  }}

申明Promise的静态方法

总共有4个静态方法: Promise.resolvePromise.rejectPromise.allPromise.race,对立返回的都是新的Promise。

class Promise {  ...  /**   * 间接resolve   */  static resolve(value) {    // 是Promise间接返回    if (value instanceof Promise) {      return value    } else if (typeof value === 'object' && typeof value.then === 'function') {      // 传入的对象含有then办法      const then = value.then      return new Promise((resolve) => {        then.call(value, resolve)      })    } else {      // 失常返回值,间接返回新的Promise在resolve这个值      return new Promise((resolve) => resolve(value))    }  }  /**   * 间接reject, 测试下Promise.reject并没做非凡解决,所以间接返回即可。   */  static reject(value) {    return new Promise((resolve, reject) => reject(value))  }  /**   * 传入数组格局的`Promise`并返回新的`Promise`实例,胜利便依照程序把值返回进去,其中一个失败则间接变成失败   */  static all(promises) {    return new Promise((resolve, reject) => {      let count = 0      let arr = []      // 依照对应的下标push到数组外面      promises.forEach((promise, index) => {        // 转换成Promise对象        Promise.resolve(promise).then((res) => {          count++          arr[index] = res          if (count === promises.length) {            resolve(arr)          }        }, err => reject(err))      })    })  }    /**   * 传入数组格局的`Promise`并返回新的`Promise`实例,胜利与失败取决第一个的实现形式   */  static race(promises) {    return new Promise((resolve, reject) => {      promises.forEach((promise, index) => {        // 转换成Promise对象        Promise.resolve(promise).then((res) => {          // 谁先执行间接resolve, 或reject          resolve(res)        }, err => reject(err))      })    })  }  ...}

Promise实现残缺代码

class Promise {  _value  _state = 'pending'  _queue = []  constructor(fn) {    if (typeof fn !== 'function') {      throw new Error('Promise resolver undefined is not a function')    }    /*       new Promise((resolve, reject) => {        resolve: 胜利        reject: 失败      })    */    fn(this._resolve.bind(this), this._reject.bind(this))  }  /**   * 接管1-2参数,第一个为胜利的回调,第二个为失败的回调   *   * @param {*} onFulfilled   * @param {*} onRejected   * @return {*}    * @memberof Promise   */  then(onFulfilled, onRejected) {    // 返回新的Promise    return new Promise((resolve, reject) => {      // 有可能曾经resolve了,因为Promise能够提前resolve,而后then办法前面注册,这个时候能够间接把值返给函数就好了      if (this._state === 'fulfilled' && onFulfilled) {        this._nextTick(onFulfilled.bind(this, this._value))        return      }      if (this._state === 'rejected' && onRejected) {        this._nextTick(onRejected.bind(this, this._value))        return      }      // 把以后Promise的then办法的参数跟新的Promise的resolve, reject存到一起,以此来做关联      this._queue.push({        onFulfilled,        onRejected,        resolve,        reject      })    })  }  /**   * 接管失败的回调   *   * @param {*} onRejected   * @return {*}    * @memberof Promise   */  catch(onRejected) {    return this.then(null, onRejected)  }  /**   * 胜利与失败都执行的回调   *   * @param {*} onDone   * @return {*}    * @memberof Promise   */  finally(onDone) {    return this.then((value) => {      onDone()      return value    }, (value) => {      onDone()      // 间接报错,能够在try catch中捕捉谬误      throw value    })  }  /**   * 间接resolve   *   * @static   * @param {*} value   * @return {*}    * @memberof Promise   */  static resolve(value) {    if (value instanceof Promise) {      return value    } else if (typeof value === 'object' && typeof value.then === 'function') {      // 传入的对象含有then办法      const then = value.then      return new Promise((resolve) => {        then.call(value, resolve)      })    } else {      return new Promise((resolve) => resolve(value))    }  }  /**   * 间接reject, 测试下reject在Promise.reject中没做非凡解决   *   * @static   * @param {*} value   * @return {*}    * @memberof Promise   */  static reject(value) {    return new Promise((resolve, reject) => reject(value))  }  /**   * 传入数组格局的`Promise`并返回新的`Promise`实例,胜利便依照程序把值返回进去,其中一个失败则间接变成失败   *   * @static   * @param {*} promises   * @memberof Promise   */  static all(promises) {    return new Promise((resolve, reject) => {      let count = 0      let arr = []      if (Array.isArray(promises)) {        if (promises.length === 0) {          return resolve(promises)        }        promises.forEach((promise, index) => {          // 转换成Promise对象          Promise.resolve(promise).then((res) => {            count++            arr[index] = res            if (count === promises.length) {              resolve(arr)            }          }, err => reject(err))        })        return      } else {        reject(`${promises} is not Array`)      }    })  }    /**   * 传入数组格局的`Promise`并返回新的`Promise`实例,胜利与失败取决第一个的实现形式   *   * @static   * @param {*} promises   * @return {*}    * @memberof Promise   */  static race(promises) {    return new Promise((resolve, reject) => {      if (Array.isArray(promises)) {        promises.forEach((promise, index) => {          // 转换成Promise对象          Promise.resolve(promise).then((res) => {            resolve(res)          }, err => reject(err))        })      } else {        reject(`${promises} is not Array`)      }    })  }  // 推入微工作  _nextTick(fn) {    if (typeof MutationObserver !== 'undefined') { // 浏览器      // 这块能够独自拿进去共用,防止不必要的开销,不然每次都须要生成节点。      const observer = new MutationObserver(fn)      let count = 1      const textNode = document.createTextNode(String(count))      observer.observe(textNode, {        characterData: true      })      textNode.data = String(++count)    } else if (typeof process.nextTick !== 'undefined') { // node      process.nextTick(fn)    } else {      setTimeout(fn, 0)    }  }  // 胜利resolve  _resolve(value) {    // 状态确定了,就不再发生变化了    if (this._state !== 'pending') return    // 下面示例外面其实返回的是一个Promise,而不是间接返回的值,所以,这里咱们须要做一个非凡解决。    // 就是如果resolve()的如果是Promise的对象,咱们须要解析Promise的后果,而后在把值传给resolve    if (typeof value === 'object' && typeof value.then === 'function') {      // 咱们能够把以后_resolve办法传递上来,因为then办法中的参数,一经下个Promise resolve,便会执行then办法对应的参数,而后把对应的值传入。      // 这样就能取到Promise中的值      // this._resove => obj.onFulfilled?.(this._value)      // this._reject => obj.onRejected?.(this._value)      value.then(this._resolve.bind(this), this._reject.bind(this))      return    }    // 通过打印测试,如果间接在线程里进行resolve, 状态跟值如同是间接就扭转了,并没有执行完主流程,在执行微工作的时候进行批改的。    // 所以把状态扭转和值的批改移出了微工作,只有在走回调的时候才通过微工作进行解决    this._state = 'fulfilled'    this._value = value    // 推入微工作    this._nextTick(() => {      this._queue.forEach((obj) => {        // 应用try catch 来捕捉onFulfilled存在函数外部谬误的状况        try {          // 承受onFulfilled返回值,如果不存在,把this._value往下传递          const val = obj.onFulfilled ? obj.onFulfilled(this._value) : this._value          // reoslve这个值,此时 onFulfilled 是以后Promise then办法中的第一个参数: Promise.then((res) => {consolle.log(res)})          // obj.resolve是新的Promise的resolve函数,这样就把then办法中的返回值传给下一个Promise          obj.resolve(val)        } catch (e) {          obj.reject(e)        }      })    })  }  // 失败reject  _reject(error) {    if (this._state !== 'pending') return    this._state = 'rejected'    this._value = error    this._nextTick(() => {      this._queue.forEach((obj) => {        try {          // 用户传入的函数外部谬误捕捉          if (obj.onRejected) {            const val = obj.onRejected(this._value)            // 以后 reject执行结束之后,会返回新的Promise,应该是能失常resolve的,所以这里要用 resolve, 不应该持续应用reject来让下个Promise执行失败流程            obj.resolve(val)          } else {            // 递归传递reject谬误            obj.reject(this._value)          }        } catch (e) {          obj.reject(e)        }      })    })  }}

残缺演示成果

博客原文地址

本我的项目残缺代码:GitHub

以上就是Promise的实现计划,当然这个跟残缺的Promises/A+标准是有区别的。这里只是用做于学习之用。

QQ群公众号
前端打杂群
冬瓜书屋
我本人新创建了一个互相学习的群,无论你是筹备入坑的小白,还是半路入行的同学,心愿咱们能一起分享与交换。
QQ群:810018802, 点击退出