JS手写Promise

145 阅读3分钟

难点与解决方案:

1. promise中包裹了异步任务的处理

  1. 实例调用then方法时,将then中的回调函数保存起来
  2. 当promise中的resolve或者reject执行时,执行then办法保存起来的回调函数
  3. 由于一个实例可以调用多次then方法,而每一个then的回调都要执行,因此存于一个数组中

2. then方法的回调返回值也是promise

  1. then返回的promise实例的状态和值,等同于then的回调返回的promis实例的状态和值

3. 异常穿透

  1. then方法中,判断第二个参数没有值(或者不是函数)
  2. 如果没有第二个参数,则重写该回调,使其为一个函数,并抛出上一个promise失败的结果,实现异常穿透

方式一:使用构造函数封装

// 定义构造函数
function Promise(executor) {
  this.PromiseState = 'pending'    // 记录状态
  this.PromiseResult = undefined    // 记录返回值
  this.callbacks = []     // 存放then的回调函数,处理异步事件,使用数组可存多个then的回调函数
  // 定义resolve函数
  function resolve(data) {
    if (this.PromiseState !== 'pending') return  // 如果状态已经改变,则不执行下面的代码
    this.PromiseState = 'fulfilled'    // 改变状态
    this.PromiseResult = data           // 存入结果值
    // 异步执行,调用then中的回调函数
    this.callbacks.forEach(item => {
      if (item.onResolve) item.onResolve(data)     // 执行then中的成功回调
    });
  }
  // 定义reject函数
  function reject(data) {
    if (this.PromiseState !== 'pending') return
    this.PromiseState = 'rejected'
    this.PromiseResult = data
    // 异步执行,调用then中的回调函数
    this.callbacks.forEach(item => {
      if (item.onReject) item.onReject(data)
    });
  }
  try {
    // 执行new promise传入的回调
    executor(resolve.bind(this), reject.bind(this))
  } catch (err) {
    reject.call(this, err)    // 记录失败原因,并改变状态
  }
}

// 定义then方法
Promise.prototype.then = function (onResolve, onReject) {
  // 保存this
  let self = this
  // 判断then传入的回调是不是函数,实现异常穿透
  if (typeof onReject !== "function") onReject = err => { throw err }
  if (typeof onResolve !== "function") onResolve = res => res
  // then方法返回一个promise
  return new Promise((resolve, reject) => {    // 使用箭头函数this指向调用then的Promise
    // 声明一个函数,用来改变then返回的promise的状态,type为then的第几个参数
    let callback = function (type) {
      try {
        let res = type(self.PromiseResult)
        // 如果then的回调函数返回了一个promise
        // 那then返回的promise的状态和值就等于这个promise的状态和值
        if (res instanceof Promise) {    
          res.then(r => {
            resolve(r)             // 改变状态为成功,并记录返回的结果
          }, e => {
            reject(e)             // 改变状态为失败,并记录返回的结果
          })
        } else {             // 回调返回的不是promise
          resolve(res)
        }
      } catch (err) {    // 回调函数抛错
        reject(err)       // 改变状态为失败
      }
    }
    // 如果promise的状态已经成功
    if (this.PromiseState === 'fulfilled') {
      callback(onResolve)
    // 如果promise状态是失败
    } else if (this.PromiseState === 'rejected') {
      callback(onReject)
    } else {  // 如果promise的状态是pending,也就是promise中有异步任务
      // 有多个回调都要保存,所以存在一个数组中
      this.callbacks.push({
        onResolve: function () {
          callback(onResolve)
        },
        onReject: function () {
          callback(onReject)
        }
      })
    }
  })
}

// 定义catch方法,调用then的异常处理方法即可
Promise.prototype.catch = function (onReject) {
  return this.then(undefined, onReject)
}

方式二:class定义类

  • 思路与构造函数封装promise一致
class Promise {
  constructor(executor) {
    this.PromiseState = 'pending'    // 记录状态
    this.PromiseResult = undefined    // 记录返回值
    this.callbacks = []   // 记录then的回调
    // 执行promise的传入的回调函数
    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject.call(this, error)
    }
  }
  resolve(data) {
    if (this.PromiseState !== "pending") return
    this.PromiseState = 'fulfilled'
    this.PromiseResult = data
    // 异步执行,调用then中的回调函数
    this.callbacks.forEach(item => {
      item.onResolve(data)
    })
  }
  reject(data) {
    if (this.PromiseState !== "pending") return
    this.PromiseState = 'rejected'
    this.PromiseResult = data
    this.callbacks.forEach(item => {
      item.onReject(data)
    })
  }
  // 定义promise的then方法
  then(onResolve, onReject) {
    let self = this
    // 处理异常穿透
    if(typeof onResolve !== 'function') onResolve=res=>res
    if(typeof onReject !== 'function') onReject=err=>{throw err}
    // then方法返回一个promis实例
    return new Promise((resolve, reject) => {
      // 处理then的参数的返回值
      function resultThen(type) {
        try {
          let res = type(self.PromiseResult) // 执行then的回调函数,并获取返回值
          if (res instanceof Promise) { // then的回调的返回值如果是promise
            res.then(r => {
              resolve(r)
            }, e => {
              reject(e)
            })
          } else {
            resolve(res)
          }
        } catch (error) {
          reject(error)
        }
      }
      // 判断promise实例的状态,并做对应处理
      if (this.PromiseState === 'fulfilled') {
        resultThen(onResolve)
      } else if (this.PromiseState === 'rejected') {
        resultThen(onReject)
      } else {  // promise是pending状态
        this.callbacks.push({   // 将then的回调保存起来
          onResolve: function () {
            resultThen(onResolve)
          },
          onReject: function () {
            resultThen(onReject)
          }
        })
      }
    })
  }
  // 定义promise的catch方法,等同于调用的then方法传入第二个参数
  catch(onReject){
    return this.then(undefined,onReject)
  }
}