Promise手写

7/25/2022

手写 promise,promise.all 等方法

promise 又被称作期约,通常用来描述一个异步操作是否成功或者失败以及其结果值。它拥有三种状态:

  • pending:待定,暂时未知结果,既未兑现,也未失败。
  • fulfilled:已兑现,表示成功
  • rejected:已拒绝,代表失败

通常我们在创建一个promise对象的时候会传入一个回调函数。其参数便是对应成功和失败的回调。当使用resolve后即成功,reject即失败。promise对象的状态一经确认不会改变。

同时我们可以调用 then 方法获取 promise 对象的结果,同时 then 方法也是返回一个 promise 对象,所以可以采用链式调用的方法.

同时 promise 也有几个静态方法比如

  • all:接收一个 iterable 类型(数组、map),返回所有成功的 promise 的结果,如果有一个失败,就立即返回失败的结果

  • any:接收同上,返回第一个执行成功的结果,若是全部失败则报错

  • allSettled:接收同上,返回所有的结果,会包含状态和结果,结果类似如下

    ;[
      { status: 'fulfilled', value: 1 },
      { status: 'rejected', reason: 2 },
    ]
    
  • race:接收同上,返回第一个执行的结果

  • resolve:返回一个带有拒原因的Promise对象

  • reject:返回一个带有成功结果的Promise对象

class RTPromise {
  // 三种状态
  status = 'pending'
  // 成功失败的回调
  successCbs = []
  errorCbs = []
  constructor(executor) {
    let resolve = (value) => {
      if (this.status === 'pending') {
        // 添加到异步任务
        queueMicrotask(() => {
          // 状态一经确定不可再改变
          if (this.status === 'pending') {
            this.status = 'fulfilled'
            this.value = value
            this.successCbs.forEach((cb) => cb())
          }
        })
      }
    }
    let reject = (err) => {
      if (this.status === 'pending') {
        queueMicrotask(() => {
          if (this.status === 'pending') {
            this.status = 'rejected'
            this.err = err
            this.errorCbs.forEach((cb) => cb())
          }
        })
      }
    }
    executor(resolve, reject)
  }
  then(onFulfilled, onRejected) {
    // 解决没有参数的情况
    onFulfilled = onFulfilled || ((v) => v)
    onRejected =
      onRejected ||
      ((err) => {
        throw err
      })
    // then方法返回一个新的promise,即链式调用
    return new RTPromise((resolve, reject) => {
      // 同步时
      if (this.status === 'fulfilled') {
        resolve(onFulfilled(this.value)) // 将上一个then函数的值返回
      }

      if (this.status === 'rejected') {
        reject(onRejected(this.err)) // 将上一个then函数的值返回
      }
      // 异步时候
      if (this.status === 'pending') {
        this.successCbs.push(() => {
          resolve(onFulfilled(this.value))
        })
        this.errorCbs.push(() => {
          reject(onRejected(this.err))
        })
      }
    })
  }
  catch(onRejected) {
    return this.then(undefined, onRejected)
  }
  finally(onFinally) {
    // 不论成功失败都执行
    return this.then(
      () => onFinally(),
      () => onFinally()
    )
  }
  static resolve(value) {
    return new RTPromise((resolve) => resolve(value))
  }
  static reject(err) {
    return new RTPromise((undefined, reject) => reject(err))
  }
  static all(RTPromises) {
    return new RTPromise((resolve, reject) => {
      const values = []
      RTPromises.forEach((RTPromise) => {
        RTPromise.then(
          // 全部正确才返回
          (res) => {
            values.push(res)
            if (values.length === RTPromises.length) resolve(values)
          },
          // 有一个错误就抛出错误
          (err) => reject(err)
        )
      })
    })
  }

  static race(RTPromises) {
    return new RTPromise((resolve, reject) => {
      RTPromises.forEach((RTPromise) => {
        RTPromise.then(
          // 谁先谁出
          (res) => resolve(res),
          (err) => reject(err)
        )
      })
    })
  }

  // 返回所有执行完成后的结果
  static allSettled(RTPromises) {
    return new RTPromise((resolve, reject) => {
      const results = []
      RTPromises.forEach((RTPromise) => {
        RTPromise.then(
          (res) => {
            results[idx] = {
              status: 'fulfilled',
              value: res,
            }
            // 需要按照对应的下标返回
            // 同时所有的内容都已完成才返回
            if(results.every(res => !!res)) resolve(results)
          },
          (err) => {
            results[idx] = {
              status: 'rejected',
              reason: err,
            }
            if(results.every(res => !!res)) resolve(results)
          }
        )
      })
    })
  }

  // 返回第一个被接收的 promise
  static any(RTPromises) {
    const errCbs = 0
    return new RTPromise((resolve, reject) => {
      RTPromises.forEach((RTPromise) => {
        RTPromise.then(res => {
          resolve(res)
        },err => {
          errCbs++
          // 当所有的都被拒绝
          if(errCbs === RTPromises.length) reject(new AggregateError(err))
        })
      })
    })
  }
}

race:返回第一个被返回的值(成功、失败都可)