手写promise

68 阅读4分钟
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
/**
* 执行函数捕获错误 
* value=>参数, fn=>函数, resolve=>成功调用, reject=>失败调用
*/
function executeFnCatchErr (value, fn, resolve, reject) {
  try {
    const result = fn(value)
    resolve(result)
  } catch (err) {
    reject(err)
  }
}
/**
* 手写promise
* 1. resolve和reject只能执行一个 通过Promise三种状态实现控制
* 2. 实现then可以多次重复调用 在then的时候把方法放进一个数组循环调用 实现状态确定后调用
* 3. 实现链式调用 then方法返回一个promise 继续.then
* 4. 实现catch方法(第二个参数err写法是promiseA+的规范,ES6为了跟容易使用理解用了catch方法,catch和err同理),
*    当第一个promise的二个参数是undefined的时候抛出错误,就会调第二个promise的err
* 5. 实现finally方法 在失败和成功回调数组里添加finally回调函数 因为catch抛出了错误,导致finally不执行 成功回调时undefined catch返回一个promise
* 6. 实现静态类方法
* 7. 实现all方法(传入一个数组,均为promise,全部resolve执行.then方法,结果跟数组顺序对应,如果有一个reject执行.catch方法)
* 8. 实现allSettled方法(新增 特性:不会执行err|catch方法,等所有的都有结果,根据返回的状态判断是失败还是成功)
* 9. 实现race方法(竞赛 只要一个有结果,不管是resolve还是reject,得到结果后,数组里会执行完毕,但是不会回调)
* 10 实现any方法(只要有一个resolve结果就调resolve,当所有都是reject会返回所有的err数组集合)
*/
class Hpromise {
  // 构造器 new的时候会直接执行 this指向新创建的实例对象 参数和new的时候参数一致 executor对应(resolve, reject) =>{}
  constructor(executor) {
    this.status = PROMISE_STATUS_PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []
    // 成功回调
    const resolve = (value) => {
      if (this.status == PROMISE_STATUS_PENDING) {
        // 把一个函数加入到微任务里 延迟调用 在本轮主线完成后执行 解决this.onFulfilled是undefined
        queueMicrotask(() => {
          if (this.status != PROMISE_STATUS_PENDING) return;
          this.status = PROMISE_STATUS_FULFILLED // 修改状态
          this.value = value
          // 执行then传递过来的回调函数 并传递value
          // this.onFulfilled(value)
          this.onFulfilledCallbacks.forEach(fn => fn())
        })
        // this.onFulfilled(value) // 这时候还没有执行then 没有给this.onFulfilled赋值 undefined
      }
    }
    // 失败回调
    const reject = (reason) => {
      if (this.status == PROMISE_STATUS_PENDING) {
        if (this.status != PROMISE_STATUS_PENDING) return;
        queueMicrotask(() => {
          this.status = PROMISE_STATUS_REJECTED // 修改状态
          this.reason = reason
          // 执行then传递过来的第二个回调函数 并传递reason
          // this.onRejected(reason)
          this.onRejectedCallbacks.forEach(fn => fn())
        })
      }
    }
    // 这里调用executor方法 并且传递resolve和reject  
    // 解决executor的报错报错 抛出执行reject
    try {
      executor(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }
  then (onFulfilled, onRejected) {
    // 实现链式调用 返回一个promise
    // 当第一个promise的二个参数是undefined的时候抛出错误,就会调第二个promise的err
    onRejected = onRejected || (err => { throw err })
    onFulfilled = onFulfilled || (value => { return value })
    return new Hpromise((resolve, reject) => {
      // 链式调用时 返回值是到第二个的resolve里 除非代码抛出错误会到第二个的reject
      // 返回第一个的返回值到第二个promise
      // 实现确定状态后的调用
      if (this.status == PROMISE_STATUS_FULFILLED) {
        // try { const value = onFulfilled(this.value); resolve(value) } catch (err) { reject(err) }
        executeFnCatchErr(this.value, onFulfilled, resolve, reject)
      }
      if (this.status == PROMISE_STATUS_REJECTED) {
        // try { const reason = onRejected(this.reason); resolve(reason) } catch (err) { reject(err) }
        executeFnCatchErr(this.reason, onRejected, resolve, reject)
      }
      // pending状态的调用
      if (this.status == PROMISE_STATUS_PENDING) {
        // 保存传过来的两个函数(成功,失败) 这里并没有执行 而是把第二个promise的resolve, reject传入 在微任务里循环调用
        this.onFulfilledCallbacks.push(() => {
          // try { const value = onFulfilled(this.value); resolve(value) } catch (err) { reject(err) }
          executeFnCatchErr(this.value, onFulfilled, resolve, reject)
        })
        this.onRejectedCallbacks.push(() => {
          // try { const reason = onRejected(this.reason); resolve(reason) } catch (err) { reject(err) }
          executeFnCatchErr(this.reason, onRejected, resolve, reject)
        })
      }
    })
  }
  catch (onRejected) {
    // 实现catch方法同理与then的第二个参数执行 只是写法不同
    return this.then(undefined, onRejected)
  }
  finally (onFinally) {
    this.then(() => { onFinally() }, () => { onFinally() })
  }
  static resolve (value) {
    return new Hpromise((resolve) => resolve(value))
  }
  static reject (reason) {
    return new Hpromise((resolve, reject) => reject(reason))
  }
  static all (promises) {
    return new Hpromise((resolve, reject) => {
      const values = []
      promises.forEach(promise => {
        promise.then(res => {
          values.push(res)
          if (values.length == promises.length) {
            resolve(values)
          }
        }).catch(err => {
          reject(err)
        })
      })
    })
  }
  static allSettled (promises) {
    return new Hpromise((resolve, reject) => {
      const values = []
      promises.forEach(promise => {
        promise.then(res => {
          values.push({ status: PROMISE_STATUS_FULFILLED, value: res })
          if (values.length == promises.length) {
            resolve(values)
          }
        }).catch(err => {
          values.push({ status: PROMISE_STATUS_REJECTED, value: err })
          if (values.length == promises.length) {
            resolve(values)
          }
        })
      })
    })
  }
  static race (promises) {
    return new Hpromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(res => {
          resolve(res)
        }).catch(err => {
          reject(err)
        })
      })
    })
  }
  static any (promises) {
    const reasons = []
    return new Hpromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(res => {
          resolve(res)
        }).catch(err => {
          reasons.push(err)
          if (reasons.length == promises.length) {
            reject(reasons)
          }
        })
      })
    })
  }
}
const promise = new Hpromise((resolve, reject) => {
  resolve(111)
  // reject(222)
})
// 普通使用
// promise.then(res => {
//   console.log('res1', res)
// }, err => {
//   console.log('res1', err)
// })

// 重复调用
// promise.then(res => {
//   console.log('res2', res)
// }, err => {
//   console.log('res2', err)
// })

// 确认状态后调用
// setTimeout(() => {
//   promise.then(res => {
//     console.log('res3', res)
//   }, err => {
//     console.log('res3', err)
//   })
// }, 1000)

// 链式调用
// promise.then(res => {
//   console.log('res4', res)
//   return 'aaaa'
// }, err => {
//   console.log('err4', err)
//   throw new Error('err msg')
//   return 'bbbb'
// }).then(res => {
//   console.log('res5', res)
// }, err => {
//   console.log('err5', err)
// })

// catch写法
// promise.then((res) => {
//   console.log('res', res)
// }).catch(err => {
//   console.log('err', err)
// })

// finally
// promise.then((res) => {
//   console.log('res', res)
// }).catch(err => {
//   console.log('err', err)
// }).finally(() => {
//   console.log('finally')
// })

// 静态类方法
// Hpromise.resolve('dw joidqw ').then((res) => {
//   console.log('res', res)
// })
// Hpromise.reject('err').then((res) => {
//   console.log('res', res)
// }, (err) => {
//   console.log('err', err)
// })
// Hpromise.reject('err').catch((err) => {
//   console.log('err', err)
// })


const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve(1111) }, 1000) })
const p2 = new Promise((resolve, reject) => { setTimeout(() => { reject(2222) }, 2000) })
const p3 = new Promise((resolve, reject) => { setTimeout(() => { resolve(3333) }, 3000) })
// all实现
// Hpromise.all([p1, p2, p3]).then((res) => {
//   console.log('res', res)
// }).catch(err => {
//   console.log('err', err)
// })

// allSettled实现
// Hpromise.allSettled([p1, p2, p3]).then((res) => {
//   console.log('res', res)
// })

// race实现
// Hpromise.race([p1, p2, p3]).then((res) => {
//   console.log('res', res)
// }).catch((err) => {
//   console.log('err', err)
// })

// any实现
Hpromise.any([p1, p2, p3]).then((res) => {
  console.log('res', res)
}).catch((err) => {
  console.log('err', err)
})