手写Promise

23 阅读1分钟

1. 最简单版本

const pending = 'pending'
const fulfilled = 'fulfilled'
const rejected = 'rejected'
class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject)
    } catch(e){
      this.reject(e)
    }
  }
  status = pending
  successFunArr = []
  failFunArr = []
  value = null
  reason = null
  resolve = (val) => {
    if (this.status !== pending) {
      return
    }
    this.value = val
    this.status = fulfilled
    const size = this.successFunArr.length
    queueMicrotask(() => {
      for(let i = 0; i< size; i++) {
        this.successFunArr[i](val)
      }
    })
  }
  reject = (reason) => {
    if (this.status !== pending) {
      return
    }
    this.reason = reason
    this.status = rejected
    const size = this.failFunArr.length
    queueMicrotask(() => {
      for(let i = 0; i< size; i++) {
        this.failFunArr[i](reason)
      }
    })
  }
  then = (onFulfilled, onRejected) => {
    const onFulfilledCallback = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    const onRejectedCallback = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
    return new MyPromise(() => {
      if (this.status === fulfilled) {
        queueMicrotask(() => {
          onFulfilledCallback(this.value)
        })
      } else if (this.status === rejected) {
        queueMicrotask(() => {
          onRejectedCallback(this.reason)
        })
      } else {
        this.successFunArr.push(onFulfilledCallback)
        this.failFunArr.push(onRejectedCallback)
      }
    })

  }
  catch = (onRejected) => {
    const onRejectedCallback = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
    this.failFunArr.push(onRejectedCallback)
  }

}
const aP = new MyPromise((resolve, reject) => {
  console.log(1)
  setTimeout(() => {
    resolve(100)
  }, 3000)
})
aP.then((v) => {
  console.log('MyPromise', v)
})
console.log(2)

2. then返回一个Promise

const pending = 'pending'
const fulfilled = 'fulfilled'
const rejected = 'rejected'
class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject)
    } catch(e){
      this.reject(e)
    }
  }
  status = pending
  successFunArr = []
  failFunArr = []
  value = null
  reason = null
  resolve = (val) => {
    if (this.status !== pending) {
      return
    }
    this.value = val
    this.status = fulfilled
    const size = this.successFunArr.length
    queueMicrotask(() => {
      for(let i = 0; i< size; i++) {
        this.successFunArr[i](val)
      }
    })
  }
  reject = (reason) => {
    if (this.status !== pending) {
      return
    }
    this.reason = reason
    this.status = rejected
    const size = this.failFunArr.length
    queueMicrotask(() => {
      for(let i = 0; i< size; i++) {
        this.failFunArr[i](reason)
      }
    })
  }
  then = (onFulfilled, onRejected) => {
    const onFulfilledCallback = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    const onRejectedCallback = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
    return new MyPromise((resolve, reject) => {
      if (this.status === fulfilled) {
        queueMicrotask(() => {
          try {
            let x = onFulfilledCallback(this.value)
            resolve(x)
          } catch(e){
            reject(e)
          }
        })
      } else if (this.status === rejected) {
        queueMicrotask(() => {
          try {
            let x = onRejectedCallback(this.reason)
            resolve(x)
          } catch(e){
            reject(e)
          }
        })
      } else {
        this.successFunArr.push((val) => {
          try {
            let x = onFulfilledCallback(val)
            resolve(x)
          } catch(e){
            reject(e)
          }
        })
        this.failFunArr.push((reason) => {
          try {
            let x = onRejectedCallback(reason)
            resolve(x)
          } catch(e){
            reject(e)
          }
        })
      }
    })

  }
  catch = (onRejected) => {
    return this.then(null, onRejected)
  }

}
const aP = new MyPromise((resolve, reject) => {
  console.log(1)
  setTimeout(() => {
    resolve(100)
  }, 3000)
})
aP.then((v) => {
  console.log('MyPromise 1', v)
  return v+ 100
}).then((v) => {
  console.log('MyPromise 2', v)
})
console.log(2)