手写Promise源码及方法

原文: 本人掘金文章

关注公众号: 微信搜索 前端工具人 ; 收货更多的干货

一、Es5语法

function MyPromise (executor) {
    this.state = 'pending'
    // 成功的值
    this.data = undefined
    // 失败的原因
    this.reason = undefined
    this.callbacks = []

    // 成功回调, state 重置为 resolved
    let resolve = (value) => {
      if (this.state !== 'pending') return
      this.state = 'resolved'
      this.data = value
      // 立即执行异步回调函数
      setTimeout(_ => {
        this.callbacks.forEach(callback => {
          callback.onResolved(value)
        })
      })
    }

    // 失败回调, state 重置为 rejected
    let reject = (reason) => {
      if (this.state !== 'pending') return
      this.state = 'rejected'
      this.reason = reason
      setTimeout(_ => {
        this.callbacks.forEach(callback => {
          callback.onRejected(reason)
        })
      })
    }

    // 如果executor执行报错,直接执行reject
    try{
      executor(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }

  // Promise原型链上的then方法,可以接收两个参数(且是回调函数),成功/失败,并且每次返回的都是一个新的Promise
  MyPromise.prototype.then = function (onResolved, onRejected) {
    let _this = this
    onResolved = typeof onResolved === 'function' ? onResolved : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason =>  console.error(reason)
    // promise对象当前状态为pending
    // 此时并不能确定调用onResolved还是onRejected,需要等待promise的状态改变
    return new MyPromise((resolve, reject) => {

       /*
       * 1、返回的Promise的结果是由onResolved/onrejected决定的
       * 2、返回的是Promise对象 (根据执结果决定Promise的返回结果)
       * 3、返回的不是Promise对象 (该值就是Promise的返回结果)
       * 4、抛出异常 异常的值为返回的结果
       */

      // 统一处理函数
      function handle (callback) {
        try {
          const result = callback(_this.data)
          if (reject instanceof MyPromise) {
            result.then(value => {
              resolve(value)
            }, reason => {
              reject(reason)
            })
          } else {
            resolve(result)
          }
        } catch (e) {
          reject(e)
        }
      }

      if (_this.state === 'resolved') {
        setTimeout(_ => {
          handle(onResolved)
        })
      }
      if (_this.state === 'rejected') {
        setTimeout(_ => {
          handle(onRejected)
        })
      }
      if (_this.state === 'pending') {
        _this.callbacks.push({
          onResolved() {
            handle(onResolved)
          },
          onRejected() {
            handle(onResolved)
          }
        })
      }
    })
  }

  // 错误捕获
  MyPromise.prototype.catch = function (onRejected) {
    return this.then(null, onRejected)
  }

  MyPromise.resolve = function (value) {
    if (value instanceof MyPromise) return value
    return new MyPromise(resolve => resolve(value))
  }

  MyPromise.reject = function (reason) {
    console.log(reason)
    return new MyPromise((resolve, reject) => reject(reason))  // 返回一个reject状态Promise对象
  }

  /*
  * Promise.all可以将多个Promise实例包装成一个新的Promise实例。
  * 同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值
  */
  MyPromise.all = function (promises) {
    if (typeof promises !== 'object' || promises.constructor !== Array) return console.error('参数需为数组!')
    let count = 0
    let values = new Array(promises.length)
    return new MyPromise((resolve,reject) => {
      promises.forEach((promise, index) => {
        MyPromise.resolve(promise).then(value => {
          count++
          values[index] = value
          if (count === promises.length) resolve(values)
        }, error => {
          reject(error)
        })
      })
    })
  }

  /*
  * Promise.race 返回数组实例中最先改变状态的实例(无论成功还是失败)
  *
  */
  MyPromise.race = function (promises) {
    return new MyPromise((resolve,reject) => {
      promises.forEach(promise => {
        MyPromise.resolve(promise).then(value => {
          resolve(value)
        }, error => {
          reject(error)
        })
      })
    })
  }

二、Es6 class 语法

class _Promise {
    constructor (executor) {
      const _this = this
      this.state = 'pending'
      // 成功的值
      this.data = undefined
      // 失败的原因
      this.reason = undefined
      this.callbacks = []

      function resolve (value) {
        if (_this.state === 'pending') return
        _this.state = 'resolved'
        _this.data = value
        setTimeout(_ => {
          _this.callbacks.forEach(callback => {
            callback.onResolved(value)
          })
        })
      }

      function reject (reason) {
        if (_this.state === 'pending') return
        _this.state = 'rejected'
        _this.reason = reason
        setTimeout(_ => {
          _this.callbacks.forEach(callback => {
            callback.onRejected(reason)
          })
        })
      }

      executor(resolve, reject)
    }
    then(onResolved, onRejected) {
      const _this = this
      onResolved = typeof onResolved === 'function' ? onResolved : value => value
      onRejected = typeof onRejected === 'function' ? onRejected : reason => console.error(reason)

      return new _Promise((resolve, reject) => {
        function handle (callback) {
          try {
            const result = callback(_this.data)
            if (reject instanceof _Promise) {
              result.then(value => {
                resolve(value)
              }, reason => {
                reject(reason)
              })
            } else {
              resolve(result)
            }
          } catch (e) {
            reject(e)
          }
        }
        if (_this.state === 'resolved') {
          setTimeout(_ => {
            handle(onResolved)
          })
        }
        if (_this.state === 'rejected') {
          setTimeout(_ => {
            handle(onRejected)
          })
        }
        if (_this.state === 'pending') {
          _this.callbacks.push({
            onResolved() {
              handle(onResolved)
            },
            onRejected() {
              handle(onResolved)
            }
          })
        }
      })
    }
    catch (onRejected) {
      return this.then(null, onRejected);
    }
    static resolve(value) {
      if (value instanceof _Promise) return value;
      return new _Promise(resolve => resolve(value)) // 返回一个resolved状态的新Promise对象
    }
    static reject(reason) {
      return new _Promise((resolve, reject) => reject(reason)); // 返回一个reject状态新Promise对象
    }

    static all(promises) {
      let count = 0
      let values = new Array(promises.length)
      return new _Promise((resolve, reject) => {
        promises.forEach((promise, index) => {
          _Promise.resolve(promise).then(value => {
            count++
            values[index] = value
            if (count === promises.length) resolve(values)
          }, reason => reject(reason))
        })
      })
    }

    static race(promises) {
      return new _Promise((resolve, reject) => {
        promises.forEach(promise => {
          _Promise.resolve(promise).then(value => resolve(value))
        }, reason => reject(reason))
      })
    }
  }

三、测试

 /* 测试 */
  window.onload = function () {
    f3()
    let p1 = new MyPromise((resolve,reject) => {
      resolve('p1 执行完毕')
    })
    let p2 = new MyPromise((resolve,reject) => {
      resolve('p2执行完毕')
    })
    let p3 = MyPromise.reject('失败')

    MyPromise.all([p1, p2]).then(res => {
      console.log(res)
    }).catch(error => {
      console.log(error)
    })

    MyPromise.race([p1, p2, p3]).then(res => {
      console.log(res)
    }).catch(error => {
      console.log(error)
    })
  }

  function f1 () {
    return new _Promise((resolve,reject) => {
      f4()
      resolve(1)
    })
  }

  function f2 () {
    console.log('f2f2f2f2f2f2f2f2')
  }

  function f4 () {
    console.log('f4f4f4f4f4f4f4f4')
  }

  function f3 () {
    let p = f1()
    p.then(res => {
      console.log(res)
    }).catch(err => {
      console.log(err)
    })
    f2()
  }
  // 测试结果
  // f4f4f4f4f4f4f4f4
  // f2f2f2f2f2f2f2f2
  // 失败
  // ["p1 执行完毕", "p2执行完毕"]
  // p1 执行完毕

参考: https://mp.weixin.qq.com/s?__biz=MzI2NTk2NzUxNg==&mid=2247488162&idx=1&sn=b0c4bdb172cb2076430569632267382d&chksm=ea941051dde39947ec94dcf3bea91250037c8bca83369fe62a61cb013fa79e13c6df5b06c78c&mpshare=1&scene=24&srcid=0822eoIZCeJt7Hy3t2Ygt3Vl&sharer_sharetime=1598055693895&sharer_shareid=50ec90ef8a78d43d2aeefdb38f1cb3a1#rd

posted @ 2020-09-17 10:38  会写代码的赖先生  阅读(207)  评论(0编辑  收藏  举报