为了实现 Promise 而实现 MyPromise

69 阅读3分钟

👋 最近重新学习了Promise对象,有了很多新的感悟

面试中我们也经常会遇到类似的题目,手写实现 Promise.xxx 诸如此类

今天主题是尝试手写实现一下大致的Promise,当作学习总结和回顾

constructor

实例化一个 Promise 对象时,我们会这么用

const promise = new Promise((resolve, reject) => {})

说明这个构造函数接收一个函数,这个函数可以拿到 resolvereject 这两个方法

promise符合 PromiseA+ 规范,维护自身的状态

class MyPromise {
  constructor(fn) {
    this.state = "pendding"
    this.value = null
    this.reason = null
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []

    const resolve = (value) => {
      if (this.state === "pendding") {
        this.state = "fulfilled"
        this.value = value
        this.onFulfilledCallbacks.forEach((callback) => {
          callback(value)
        })
      }
    }

    const reject = (reason) => {
      if (this.state === "pendding") {
        this.state = "rejected"
        this.reason = reason
        this.onRejectedCallbacks.forEach((callback) => {
          callback(reason)
        })
      }
    }

    try {
      fn(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }
}

then

.then 方法返回一个新的 Promise,因此我们可以链式调用

该方法还有两个参数,状态变更为 fulfilled时候的回调函数和为 rejected 时候的回调函数

then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => value
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason
          }

    const promise2 = new MyPromise((resolve, reject) => {
      if (this.state === "onFulfilled") {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value)
            this.resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0)
      } else if (this.state === "onRejected") {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason)
            this.resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0)
      } else if (this.state === "pendding") {
        this.onFulfilledCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value)
              this.resolvePromise(promise2, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0)
        })
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason)
              this.resolvePromise(promise2, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0)
        })
      }
    })

    return promise2
  }

resolvePromise

.then 方法中,有一个 resolvePromise 用来处理回调函数返回的结果

  resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
      return reject(new TypeError("Chaining cycle detected for promise"))
    }
    let called = false
    if (x instanceof MyPromise) {
      x.then(
        (y) => {
          if (called) return
          called = true
          this.resolvePromise(promise2, y, resolve, reject)
        },
        (reason) => {
          if (called) return
          called = true
          reject(reason)
        }
      )
    } else if (x && (typeof x === "object" || typeof x === "function")) {
      try {
        const then = x.then
        if (typeof then === "function") {
          then.call(
            x,
            (y) => {
              if (called) return
              called = true
              this.resolvePromise(promise2, y, resolve, reject)
            },
            (reason) => {
              if (called) return
              called = true
              reject(reason)
            }
          )
        } else {
          resolve(x)
        }
      } catch (error) {
        if (called) return
        called = true
        reject(error)
      }
    } else {
      resolve(x)
    }
  }

catch

.catch 方法其实就是 .then 方法只传递第二个参数

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

finally

.finally 方法无论 Promise 结果如何,都会触发

  finally(fn) {
    return this.then(
      (value) => {
        return MyPromise.resolve(fn()).then(() => value)
      },
      (reason) => {
        return MyPromise.resolve(fn()).then(() => {
          throw reason
        })
      }
    )
  }

resolve

Promise.resolve 是 Promise 对象的静态方法,将传入的参数转换成 Promise 对象返回

static resolve(value) {
  if (value instanceof MyPromise) return value
  return new MyPromise((resolve) => resolve(value))
 }

reject

Promise.reject 是 Promise 对象的静态方法,将传入的参数当作 reject 的理由抛出

static reject(reason) {
  return new MyPromise((_, reject) => reject(reason))
}

all

Promise.all 接收一个 promise 数组,所有结果都为 fulfilled 时会返回所有的结果

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(TypeError("Arguments must be Array"))
      }

      let promisesCounter = 0
      let promisesNum = promises.length
      const resolvedRes = []
      for (let i = 0; i < promisesNum; i++) {
        MyPromise.resolve(promises[i]).then((value) => {
          promisesCounter++
          resolvedRes.push(value)
          if (promisesCounter === promisesNum) {
            return resolve(resolvedRes)
          }
        }, reject)
      }
    })
  }

allSettled

Promise.allSettled 方法接收一个 promise 数组,不论结果如何都会返回最终结果

  static allSettled(promises) {
    return new MyPromise((resolve) => {
      if (!Array.isArray(promises)) return resolve([])

      let promisesNum = promises.length
      let promisesCounter = 0
      const res = []
      for (let i = 0; i < promisesNum; i++) {
        MyPromise.resolve(promises[i]).then(
          (value) => {
            promisesCounter++
            res.push({ state: "fulfilled", value })
            if (promisesCounter === promisesNum) {
              return resolve(res)
            }
          },
          (reason) => {
            promisesCounter++
            res.push({ state: "rejected", reason })
            if (promisesCounter === promisesNum) {
              return resolve(res)
            }
          }
        )
      }
    })
  }

race

Promise.race 方法接收一个 promise 数组,返回最先处理完成的结果,无论是什么状态

static race(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) return reject(TypeError("Argument must be Array"))

      for (let i = 0; i < promises.length; i++) {
        MyPromise.resolve(promises[i]).then(resolve, reject)
      }
    })
  }

any

Promise.any 方法接收一个 promise 数组,只要任何一个 promise 状态为 fulfilled,就返回他,如果所有的状态都为 rejected,则抛出一个错误

  static any(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) return reject(TypeError("Argument must be Array"))

      let rejectedCounter = 0
      let promisesNum = promises.length
      let rejectedRes = []
      for (let i = 0; i < promisesNum; i++) {
        MyPromise.resolve(promises[i]).then(resolve, (reason) => {
          rejectedRes.push(reason)
          rejectedCounter++
          if (rejectedCounter === promisesNum) {
            // all promises rejected
            return reject(new AggregateError(rejectedRes))
          }
        })
      }
    })
  }

🎉 结束,如有问题欢迎留言,指正。