手写promise源码

169 阅读5分钟

promise是基于发布订阅模式,它是一个类,有3个状态,pending(默认等待状态)、resolve(成功)、reject(失败),只用在pending的时候,状态才能改变。promise.then方法是执行函数执行后的回调函数执行收集,promise调用执行如下:

const promise = new Promise((resolve,reject) => {
  resolve('ok')
})
promise.then((data) => { // 有两个参数1成功2失败
  console.log(data)
},(error) => {
  console.log(error)
})
// 打印出ok

基础源码如下:

// 三个状态
const PENDING = 'PENDING' // 默认状态
const FULFILLED = 'FULFILLED' // 成功
const REJECT = 'REJECT' // 失败
class myPromise{
  constructor(exector) { // exector执行器,是一个方法,默认立即执行
    this.state = PENDING
    this.successData = undefined // 保存成功的信息
    this.errorData = undefined // 保存失败的信息
    // 改变状态
    const resolve = (value) => {
      if (this.state === PENDING)
      this.successData = value
      this.state = FULFILLED
    }
    const reject = (error) => {
      this.errorData = error
      this.state = REJECT
    }
    exector(resolve, reject) // 执行器有两个参数,resolve,reject
  }
  then(resolveFn, rejectFn) {
    // 获取到数据,成功的数据,还是失败的数据
    if (this.state === FULFILLED) {
      return resolveFn(this.successData)
    }
    if (this.state === REJECT) {
      return rejectFn(this.errorData)
    }

  }
}

下面解决promise里的执行函数是异步的情况,在执行then方法时,在等待的状态中,报执行的方法受集起来,promise类里面定义2个变量resolveList(收集获取成功数据的方法),rejectList(收集获取数据失败的方法),执行成功方法resolve时,遍历resolveList数组执行,执行失败方法reject时,遍历rejectList数组执行,并传入获得的相应数据,代码如下:

// 三个状态
const PENDING = 'PENDING' // 默认状态
const FULFILLED = 'FULFILLED' // 成功
const REJECT = 'REJECT' // 失败
class myPromise{
  constructor(exector) { // exector执行器,是一个方法,默认立即执行
    this.state = PENDING
    this.successData = undefined // 保存成功的信息
    this.errorData = undefined // 保存失败的信息
    this.resolveList = []
    this.rejectList = []
    // 改变状态
    const resolve = (value) => {
      if (this.state === PENDING)
      this.successData = value
      this.state = FULFILLED
      this.resolveList.forEach(fn => fn(this.successData))
    }
    const reject = (error) => {
      this.errorData = error
      this.state = REJECT
      this.rejectList.forEach(fn => fn(this.successDerrorDataata))
    }
    exector(resolve, reject) // 执行器有两个参数,resolve,reject
  }
  then(resolveFn, rejectFn) {
    // 获取到数据,成功的数据,还是失败的数据
    if (this.state === FULFILLED) {
      resolveFn(this.successData)
    }
    if (this.state === REJECT) {
      rejectFn(this.errorData)
    }
    if (this.state === PENDING) {
      this.rejectList.push(rejectFn)
      this.resolveList.push(resolveFn)
    }

  }
}

链式调用,解决地狱回调的问题。then方法中成功回调或者失败的回调,返回一个promise,这个promise就会采用返回promise成功或者失败的值,传递到下一个then中,的成功回调或者失败的回调,返回的是一个普通的值(不是promise),走下一个then中成功的回调,then方法中,成功回调或者失败的回调在执行的时候出现错误,走下一个then中的失败的回调。

  • 1、then返回的是一个常量promise,exector是一个立即执行函数,所以把then里面的执行函数内容放到promise里的exector里,把新建的myPromise对象的exector执行内容是第一个myPromise的then方法里面的执行内容,把第一个myPromise里面then的获取成功和失败数据执行的函数添加到对应的resolveList与rejectList中,then里面的新建的myPromise的then方法放到相应的新建的myPromise函数作用遇对象上,如果第一个myPromise状态改变,将会遍历执行第一个函数作用域里的resolveList与rejectList中的函数,执行函数代码里有第二个myPromise对象里的改变状态的resolve与reject函数,执行过程中,第二个myPromise里的状态将改变,也将遍历执行第二个myPromise作用域中的resolveList与rejectList里的函数,从而执行第二个then里的代码片段,以此类推,有无数个then的情况,代码如下:
// 三个状态
const PENDING = 'PENDING' // 默认状态
const FULFILLED = 'FULFILLED' // 成功
const REJECT = 'REJECT' // 失败
class myPromise{
  constructor(exector) { // exector执行器,是一个方法,默认立即执行
    this.state = PENDING
    this.successData = undefined // 保存成功的信息
    this.errorData = undefined // 保存失败的信息
    this.resolveList = []
    this.rejectList = []
    // 改变状态
    const resolve = (value) => {
      if (this.state === PENDING)
      this.successData = value
      this.state = FULFILLED
      this.resolveList.forEach(fn => fn())
    }
    const reject = (error) => {
      this.errorData = error
      this.state = REJECT
      this.rejectList.forEach(fn => fn())
    }
    exector(resolve, reject) // 执行器有两个参数,resolve,reject
  }
  then(resolveFn, rejectFn) {
    let promise2 = new myPromise((resolve, reject) => { // 立即执行
      // 获取到数据,成功的数据,还是失败的数据
      if (this.state === FULFILLED) {
        let x = resolveFn(this.successData)
        resolve(x)
      }
      if (this.state === REJECT) {
        let x =  rejectFn(this.errorData)
        reject(x)
      }
      if (this.state === PENDING) {
        this.resolveList.push(() => {
          let x = resolveFn(this.successData)
          resolve(x)
        })
        this.rejectList.push(() => {
          let x = rejectFn(this.errorData)
          reject(x)
        })
      }
    })
    return promise2
  }
}

下面代码将输出 OK 100

      const promise = new myPromise((resolve,reject) => {
         setTimeout(() => {
          resolve('OK')
         }, 1000)
      }).then((data) => {
        console.log(data)
        return 100
      }).then((data) => {
        console.log(data)
      })
  • 2、then返回的是一个promise,比如下列代码:
      const promise = new myPromise((resolve,reject) => {
         setTimeout(() => {
          resolve('OK')
         }, 1000)
      }).then((data) => {
        console.log(data)
        return new myPromise((resolve,reject)=> {
          resolve(100)
        })
      }).then((data) => {
        console.log(data)
      })

源码then方法就有问题,必须判断返回类型,如果then里面的回调函数返回类型是promise,则执行回调函数返回的promise执行成功或者失败后,执行then里面定义的promise的作用域下的resolve,reject方法,代码如下:

// 三个状态
const PENDING = 'PENDING' // 默认状态
const FULFILLED = 'FULFILLED' // 成功
const REJECT = 'REJECT' // 失败
// 判断then里面的返回值是否是promise,还是普通值,并执行不同的操作
function resolvePromise(x, promise2,resolve,reject) {
  // 1普通值 2 promise
  // 1 处理 返回值, x 如果等于promise2,提示错误
  if (x === promise2) {
    return reject(new TypeError('同一个promise'))
  }
  // 判断x是普通值,还是promise
  if (typeof x === 'object' && x !== null) {
    // 执行成功回调和失败的回调有错误,有错误执行下一个
    try {
      let then = x.then
      if (typeof then === 'function') {
        then.call(x, (r) => {
          resolve(r)
        }, (j) => {
          reject(j)
        })
      } else {
        resolve(x)
      }
    } catch(e) {
      reject(e)
    }
  } else {
    resolve(x)
  }
}
class myPromise{
  constructor(exector) { // exector执行器,是一个方法,默认立即执行
    this.state = PENDING
    this.successData = undefined // 保存成功的信息
    this.errorData = undefined // 保存失败的信息
    this.resolveList = []
    this.rejectList = []
    // 改变状态
    const resolve = (value) => {
      if (this.state === PENDING)
      this.successData = value
      this.state = FULFILLED
      this.resolveList.forEach(fn => fn())
    }
    const reject = (error) => {
      this.errorData = error
      this.state = REJECT
      this.rejectList.forEach(fn => fn())
    }
    exector(resolve, reject) // 执行器有两个参数,resolve,reject
  }
  then(resolveFn, rejectFn) {
    let promise2 = new myPromise((resolve, reject) => { // 立即执行
      // 获取到数据,成功的数据,还是失败的数据
      if (this.state === FULFILLED) {
        try{
          let x = resolveFn(this.successData)
          resolvePromise(x, promise2, resolve, reject)
        } catch(e) {
          reject(e)
        }
      }
      if (this.state === REJECT) {
        try{
          let x = rejectFn(this.errorData)
          resolvePromise(x, promise2, resolve, reject)
        } catch(e) {
          reject(e)
        }
      }
      if (this.state === PENDING) {
        this.resolveList.push(() => {
          try{
            let x = resolveFn(this.successData)
            resolvePromise(x, promise2, resolve, reject)
          } catch(e) {
            reject(e)
          }
        })
        this.rejectList.push(() => {
          try{
            let x = rejectFn(this.errorData)
            resolvePromise(x, promise2, resolve, reject)
          } catch(e) {
            reject(e)
          }
        })
      }
    })
    return promise2
  }
}