手动实现promise

195 阅读7分钟

promise的实现思路

  1. promise是一个类,传入一个函数,函数会立即执行。有两个固定参数resolve和reject

  2. promise执行的时候有三种状态 进行中 pending 成功 fulfilled 失败 rejected。 状态变更只有以下两种,且是不可逆的 ① pending => fulfilled ② pending => rejected

  3. resolve是用来把状态更改为成功的函数。 reject是用来把状态更改为失败的函数

  4. then方法是根据状态,来执行成功和失败回调函数

  5. 成功的回调函数能接收到状态变更时传递的值 失败的回调函数能接收到状态变更为失败时传递的值

  6. 在状态还是pending的情况下,即进行异步操作的时候,要把成功和失败的回调函数存储起来,然后在状态变更时,依次执行回调

  7. 实现链式调用then方法,即在调用then方法的时候,要返回一个promise对象。上一个then方法的返回值,是下一个then的value

  8. 链式调用then方法的参数可以不传,变为可选参数。一直把第一个的返回值,原封不动的返回给下一个then

  9. finally方法,传递一个函数,返回一个promise对象和上一个promise返回的值(如果有的话)

  10. promise.resolve方法,作用是将现有对象转为 Promise 对象。传递一个参数,返回一个promise对象

  11. promise.all方法 传递一个数组,按照数组里面的顺序,处理完后,按照顺序返回结果。如果是普通值,则直接返回,如果是promise,则处理后返回。需要等数组里的元素全部变成resolve时返回,如果有一个状态为reject,则直接返回reject

  12. promise.race方法 传递一个数组,如果是普通值,则变成promise返回,如果是promise,则处理后返回。只要有一个的状态变了,就返回那个

  13. promise.first方法,将多个 Promise 实例,包装成一个新的 Promise 实例,只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态。

  14. promise.last方法,将多个 Promise 实例,包装成一个新的 Promise 实例,获取最后一个 promise 实例的状态,并将其作为包装实例的状态返回

  15. promise.none方法,将多个 Promise 实例,包装成一个新的 Promise 实例,获取第一个状态为 fulfilled 状态的实例,将其作为包装实例的 rejected 状态返回, 如果所有实例状态都为 rejected ,则返回一个数组,将其作为包装实例的 fulfilled 状态返回

const PENDING = 'pending' // 等待中
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败
class myPromise {
  constructor(init) {
    try { // 捕获初始化发生错误的时候
      init(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }
  // promise 状态
  status = PENDING
  // 状态变更为成功时传递的值
  resolveData = undefined
  // 状态变更为失败时,传递的错误日志
  error = undefined
  // 成功回调函数,异步情况下会有多个
  successCallback = []
  // 失败回调函数,异步情况下会有多个
  failCallback = []

  //resolve和reject写成箭头函数的原因是:让this指向myPromise。因为在new myPromise的时候是直接执行了这两个函数,会导致它的this指向window,所以这里得改变一下指向
  resolve = resolveData => {
    // 如果状态不是等待,停止执行
    if(this.status !== PENDING) return
    // 更改状态为成功
    this.status = FULFILLED
    // 接收成功后返回的值
    this.resolveData = resolveData
    // 异步情况时,如果存在就,执行成功回调函数
    while(this.successCallback.length) { // 依次执行数组里面所有的回调
      // this.successCallback.shift()(this.resolveData)  // 这个写法是不接收then的返回值的写法
      this.successCallback.shift()()  // 这个写法是接收then的返回值的写法
    }
  }

  reject = error => {
    // 如果状态不是等待,停止执行
    if(this.status !== PENDING) return
    // 更改状态为失败
    this.status = REJECTED
    // 接收失败后返回的值
    this.error = error
    // 异步情况时,如果存在就,执行失败回调函数
    while(this.failCallback.length) { // 依次执行数组里面所有的回调
      // this.failCallback.shift()(this.error)  // 这个写法是不接收then的返回值的写法
      this.failCallback.shift()()  // 这个写法是接收then的返回值的写法
    }
  }

  // 这里不用箭头函数的原因是:then方法是new myPromise直接调用的,所以this本来就指向myPromise
  then(successCallback, failCallback) {
    // then方法的参数可以不传,变为可选参数
    successCallback = successCallback ? successCallback : value => value
    failCallback = failCallback ? failCallback : err => { throw err }
    let promise2 = new myPromise((resolve, reject)=>{ //实现链式调用

      if(this.status === FULFILLED) { // 执行成功的回调

        setTimeout(() => { // promise2 是自己本身,但是由于这里是同步执行的,拿不到promise2这个变量,因为还没执行完,所以把这部分变为异步的
          try {
            // 接收上一个then方法的返回值,作为下次then的value
            let result = successCallback(this.resolveData)
            //判断返回的结果
            this.handleReturnThen(promise2, result, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0);

      }else if(this.status === REJECTED) { // 执行失败的回调
        
        setTimeout(() => { // promise2 是自己本身,但是由于这里是同步执行的,拿不到promise2这个变量,因为还没执行完,所以把这部分变为异步的
          try {
            // 接收上一个then方法的返回值,作为下次then的value
            let result = failCallback(this.error)
            //判断返回的结果
            this.handleReturnThen(promise2, result, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0);

      }else {
        // 等待。把成功和失败的回调函数存起来, 因为promise可以多次调用,所以回调函数会有多个。而同步情况下会一个个执行,所以不用处理,异步情况下就要把回调函数都存起来
        // 下面这个写法是不接收then的返回值的写法
        // this.successCallback.push(successCallback)
        // this.failCallback.push(failCallback)

        // 下面这个写法是要接收then的返回值的写法
        this.successCallback.push(()=>{
          setTimeout(() => { // promise2 是自己本身,但是由于这里是同步执行的,拿不到promise2这个变量,因为还没执行完,所以把这部分变为异步的
            try {
              // 接收上一个then方法的返回值,作为下次then的value
              let result = successCallback(this.resolveData)
              //判断返回的结果
              this.handleReturnThen(promise2, result, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0);
        })
        
        this.failCallback.push(()=>{
          setTimeout(() => { // promise2 是自己本身,但是由于这里是同步执行的,拿不到promise2这个变量,因为还没执行完,所以把这部分变为异步的
            try {
              // 接收上一个then方法的返回值,作为下次then的value
              let result = failCallback(this.error)
              //判断返回的结果
              this.handleReturnThen(promise2, result, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0);
        })
      }

    })

    return promise2
  }

  catch(failCallback) {
    return this.then(undefined, failCallback)
  }

  finally (callback) { // 不管是请求成功还是失败都会执行
    return this.then(
      // 这里是处理传递的参数后,返回一个promise对象,并把上一个返回值原样返回给下一个
      value => myPromise.resolve(callback()).then(() => value),
      error => myPromise.resolve(callback()).then(() => { throw error })
    )
  }

  static resolve (data) {
    // 如果没有参数,默认返回undefined
    data = data ? data : undefined
    // 如果参数是promise对象则直接返回,如果是普通值则经过处理后返回一个promise
    if(data instanceof myPromise) return data
    return new myPromise((resolve) => {
      resolve(data)
    })
  }

  static all (array) {
    // 要返回的数组
    let result = []
    // 用来处理异步情况的中间值
    let index = 0
    return new myPromise((resolve, reject) => {
      // 往数组按原来的顺序添加返回结果
      function addData(key, value) { 
        result[key] = value
        index++
        if(index == array.length) {//判断promise是否全部执行完,因为只有异步操作执行完了,才会执行addData,然后再执行resolve
          resolve(result)
        }
      }
      for (let key in array) {
        if (array[key] instanceof myPromise) { //如果数组里的元素是promise对象,则处理后返回
          array[key].then(
            value => addData(key, value),
            error => reject(error)
          )
        }else { // 直接返回
          addData(key, array[key])
        }
      } 
    })
  }

  static race(array) {
    return new myPromise((resolve, reject) => {
      for (let key in array) {
        if (array[key] instanceof myPromise) { //如果数组里的元素是promise对象,则处理后返回
          array[key].then(
            value => resolve(value),
            error => reject(error)
          )
        }else { // 直接返回
          resolve(array[key])
        }
      } 
    })
  }
  
  static first(promiseList) => {
      return new myPromise((resolve, reject) => {
        let num = 0
        const len = promiseList.length
        promiseList.forEach((pms) => {
          myPromise.resolve(pms)
            .then(resolve)
            .catch(() => {
              num++
              if (num === len) {
                reject('AggregateError: All promises were rejected')
              }
            })
        })
      })
    }
    
    static last(promiseList) => {
      return new myPromise((resolve, reject) => {
        let num = 0
        const len = promiseList.length

        const fn = (res, bol) => {
          if (++num === len) {
            bol ? resolve(res) : reject(res)
          }
        }

        promiseList.forEach((pms) => {
          myPromise.resolve(pms)
            .then((res) => {
              fn(res, true)
            })
            .catch((err) => {
              fn(err, false)
            })
        })
      })
    }
    
    static none(promiseList) => {
      return myPromise.all(
        promiseList.map((pms) => {
          return new myPromise((resolve, reject) => {
            // 将pms的resolve和reject反过来
            return myPromise.resolve(pms).then(reject, resolve)
          })
        })
      )
    }

  handleReturnThen = (promise, result, resolve, reject) => {
    // 判断返回值是普通值,还是promise对象
    // 如果是普通值,则直接返回
    // 如果是promise(不能返回自己本身),则运行,并返回对应的结果。
    if(promise === result) {
      return reject(new TypeError('不能返回自己本身'))
    }
    if(result instanceof myPromise) {
      result.then(resolve, reject)
    }else {
      resolve(result)
    }
  }
}