#还在手写 promise 呢

#myPromise

const STATES = {
  pending: 'pending',
  fulfilled: 'fulfilled',
  rejected: 'rejected',
}

function MyPromiseError(message) {
  return `Uncaught (in myPromise) ${message}`
}

class myPromise {
  // 初始化state为等待态
  state = STATES.pending
  // 成功的值
  value = undefined
  // 失败的原因
  reason = undefined
  // onFulfilled事件订阅者
  onFulfilledCallbacks = []
  // onRejected事件订阅者
  onRejectedCallbacks = []

  constructor(executor) {
    if (typeof executor !== 'function') {
      throw '参数executor不是函数'
    }

    // 成功
    const resolve = (value) => {
      if (this.state === STATES.pending) {
        this.value = value
        this.state = STATES.fulfilled

        // 发布onFulfilled事件通知
        this.onFulfilledCallbacks.forEach((fn) => fn())
      }

      console.log('resolve', this.state, this.value, this.reason)
    }

    // 失败
    const reject = (reason) => {
      if (this.state === STATES.pending) {
        this.reason = reason
        this.state = STATES.rejected
        console.log(222222, this.state, this.reason)

        // 发布onRejected事件通知
        this.onRejectedCallbacks.forEach((fn) => fn())
      }

      // ? promise如何实现的报错提示,promise会先返回值再提示报错,普通值和异步值都是
      // 此处模拟实现则是普通值是先提示报错再返回,因为先执行console.error才执行完,异步值才是先返回再报错
      console.error(MyPromiseError(reason))

      console.log('reject', this.state, this.value, this.reason)
    }

    try {
      // 立即执行回调executor
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }

  then(onFulfilled, onRejected) {
    console.log('---', 'then', '---')

    if (typeof onFulfilled !== 'function') {
      onFulfilled = (value) => value
    }
    if (typeof onRejected !== 'function') {
      onRejected = (reason) => {
        throw reason
      }
    }

    // 实现链式调用
    const promise2 = new myPromise((resolve, reject) => {
      // 成功的任务立即执行onFulfilled回调并返回
      if (this.state === STATES.fulfilled) {
        try {
          console.log('onFulfilled', this.state, this.value, this.reason)

          const x = onFulfilled(this.value)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      }

      // 失败的任务立即执行onRejected回调并返回
      if (this.state === STATES.rejected) {
        try {
          console.log('onRejected', this.state, this.value, this.reason)

          const x = onRejected(this.reason)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      }

      // 还没有结果的异步任务
      if (this.state === 'pending') {
        console.log('异步事件等待完成', this.state, this.value, this.reason)

        // 订阅onFulfilled事件
        this.onFulfilledCallbacks.push(() => {
          try {
            const x = onFulfilled(this.value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })

        // 订阅onRejected事件
        this.onRejectedCallbacks.push(() => {
          try {
            const x = onRejected(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
    })

    console.log('---', '---')

    return promise2
  }

  catch(onRejected) {
    // 就是一个只处理失败态的 then
    return this.then(undefined, onRejected)
  }

  // ! 需要resolvePromise支持
  finally(onFinally) {
    // 就是一个,成功和失败都执行onFinally,且返回一个onFinally返回值的then
    return this.then(
      (value) => myPromise.resolve(onFinally()).then(() => value),
      (reason) =>
        myPromise.resolve(onFinally()).then(() => {
          throw reason
        }),
    )
  }

  static resolve(value) {
    return new myPromise((resolve, reject) => {
      resolve(value)
    })
  }

  static reject(value) {
    return new myPromise((resolve, reject) => {
      reject(value)
    })
  }

  static all(promises) {
    return new myPromise((resolve, reject) => {
      const result = []
      // 记录完成次数
      let count = 0

      const handleResult = (index, value) => {
        result[index] = value
        count++
        // 全部完成则resolve
        if (count === promises.length) {
          resolve(result)
        }
      }

      for (let i = 0; i < promises.length; i++) {
        // 获取每一个异步任务
        const p = promises[i]

        if (p && typeof p.then === 'function') {
          // 异步值,异步结束获取结果
          p.then((value) => {
            handleResult(i, value)
          }, reject) // 有一个失败则直接reject
        } else {
          // 普通值,直接获取结果
          handleResult(i, p)
        }
      }
    })
  }

  static allSettled(promises) {
    return new myPromise((resolve, reject) => {
      const result = new Array(promises.length)
      // 记录完成次数
      let count = 0

      const handleResult = (index, value) => {
        result[index] = value
        count++
        // 全部完成则resolve
        if (count === promises.length) {
          resolve(result)
        }
      }

      for (let i = 0; i < promises.length; i++) {
        // 获取每一个异步任务
        const p = promises[i]

        if (p && typeof p.then === 'function') {
          // 异步值,异步结束获取结果
          p.then((value) => {
            handleResult(i, value)
          }).catch((reason) => {
            handleResult(i, reason)
          })
        } else {
          // 普通值,直接获取结果
          handleResult(i, p)
        }
      }
    })
  }

  static race(promises) {
    return new myPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        // 获取每一个异步任务
        const p = promises[i]

        if (p && typeof p.then === 'function') {
          // 异步值,使用第一个触发then的
          p.then(resolve, reject)
        } else {
          // 普通值,直接获取结果
          resolve(p)
        }
      }
    })
  }

  static any(promises) {
    const rejectedArr = new Array(promises.length)

    return new myPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        // 获取每一个异步任务
        const p = promises[i]

        if (p && typeof p.then === 'function') {
          // 异步值,使用第一个成功的,失败的存到数组直到全部失败则返回
          p.then(resolve, (reason) => {
            rejectedArr[i] = reason
            if (rejectedArr.length === promises.length) {
              reject(rejectedArr)
            }
          })
        } else {
          // 普通值,直接获取结果
          resolve(p)
        }
      }
    })
  }
}

function resolvePromise(promise2, x, resolve, reject) {
  // 根据返回值 x 的情况,调用 promise2 的 resolve 或 reject 函数

  // 返回值循环引用
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }

  // 返回值 x 是对象或函数的情况
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      const then = x.then
      if (typeof then === 'function') {
        // then 是函数:就认为 x 为 Promise 类型

        // 返回值 x 为 Promise,调用 then 看结果
        then.call(
          x,
          (y) => {
            resolve(y) // 成功
          },
          (r) => {
            reject(r) // 失败
          },
        )
      } else {
        resolve(x) // 普通值
      }
    } catch (e) {
      reject(e)
    }
  } else {
    console.log('应该是普通值')
    // 普通值
    resolve(x)
  }
}

#resolvePromise

resolvePromise 解决 promise 循环引用等等 问题

如下,如果 then 的返回值是 p2,那么因为 p2 一直是 pending,所以在 then 中发布了 onFulfilled 事件后一直无法完成,应该报循环引用错误

let p = new Promise((resolve) => {
  resolve(0)
})

var p2 = p.then((data) => {
  // 循环引用,自己等待自己完成,一辈子完不成
  return p2
})

如果没处理则无限循环了

所以我们应该根据 then 中方法的返回值 x ,决定 promise2 执行成功/失败处理

function resolvePromise(promise2, x, resolve, reject) {
  // 根据返回值 x 的情况,调用 promise2 的 resolve 或 reject 函数

  // 返回值循环引用
  if (promise2 === x) {
    return reject(new TypeError('循环引用'))
  }

  // 返回值 x 是对象或函数的情况
  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      const then = x.then
      if (typeof then === 'function') {
        // then 是函数:就认为 x 为 Promise 类型

        // 返回值 x 为 Promise,调用 then 看结果
        then.call(
          x,
          (y) => {
            resolve(y) // 成功
          },
          (r) => {
            reject(r) // 失败
          },
        )
      } else {
        resolve(x) // 普通值
      }
    } catch (e) {
      reject(e)
    }
  } else {
    console.log('应该是普通值')
    // 普通值
    resolve(x)
  }
}

但是在 new promise 时,promise2 还没有完成初始化,所以 resolvePromise 中不能访问到 promise2

创建新宏任务在下一个事件循环中执行,这样调用 resolvePromise 时,promise2 一定是创建完成的

// 实现链式调用
const promise2 = new myPromise((resolve, reject) => {
  // 成功的任务立即执行onFulfilled回调并返回
  if (this.state === STATES.fulfilled) {
    // 创建新宏任务在下一个事件循环中执行,这样调用 resolvePromise 时,promise2 一定是创建完成的
    setTimeout(() => {
      try {
        const x = onFulfilled(this.value)
        // 根据返回值x类型来选择逻辑
        resolvePromise(promise2, x, resolve, reject)
      } catch (e) {
        reject(e)
      }
    }, 0)
  }

  // 失败的任务立即执行onRejected回调并返回
  if (this.state === STATES.rejected) {
    setTimeout(() => {
      try {
        const x = onRejected(this.reason)
        resolvePromise(promise2, x, resolve, reject)
        console.log(11111, this.state, this.reason)
      } catch (e) {
        reject(e)
      }
    }, 0)
  }

  // 还没有结果的异步任务
  if (this.state === 'pending') {
    // 订阅onFulfilled事件
    this.onFulfilledCallbacks.push(() => {
      setTimeout(() => {
        try {
          const x = onFulfilled(this.value)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      }, 0)
    })

    // 订阅onRejected事件
    this.onRejectedCallbacks.push(() => {
      setTimeout(() => {
        try {
          const x = onRejected(this.reason)
          resolvePromise(promise2, x, resolve, reject)
        } catch (e) {
          reject(e)
        }
      }, 0)
    })
  }
})

#all

批量执行 Promise,返回一个 Promise 实例,里面值为输入顺序的数组 全部成功才算成功,返回全部执行结果 有一个失败就算失败,返回第一个失败结果

static all(promises) {
    return new myPromise((resolve, reject) => {
      const result = new Array(promises.length)
      // 记录完成次数
      let count = 0

      const handleResult = (index, value) => {
        result[index] = value
        count++
        // 全部完成则resolve
        if (count === promises.length) {
          resolve(result)
        }
      }

      for (let i = 0; i < promises.length; i++) {
        const p = promises[i]

        if (p && typeof p.then === 'function') {
          // 异步值,异步结束获取结果
          p.then((value) => {
            handleResult(i, value)
          }, reject) // 有一个失败则直接reject
        } else {
          // 普通值,直接获取结果
          handleResult(i, p)
        }
      }
    })
  }

#allsettled

批处理 promise,返回一个 Promise 实例,里面值为输入顺序的数组 存在失败结果也会拿到全部执行结果

static allsettled(promises) {
    return new myPromise((resolve, reject) => {
      const result = new Array(promises.length)
      // 记录完成次数
      let count = 0

      const handleResult = (index, value) => {
        result[index] = value
        count++
        // 全部完成则resolve
        if (count === promises.length) {
          resolve(result)
        }
      }

      for (let i = 0; i < promises.length; i++) {
        const p = promises[i]

        if (p && typeof p.then === 'function') {
          // 异步值,异步结束获取结果
          p.then((value) => {
            handleResult(i, value)
          }).catch((reason) => {
            handleResult(i, reason)
          })
        } else {
          // 普通值,直接获取结果
          handleResult(i, p)
        }
      }
    })
  }

#race

批处理 promise,返回一个 Promise 实例,里面值为最快完成的值,同步时为第一个 无论成功还是失败,谁快就返回谁

static race(promises) {
    return new myPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        const p = promises[i]

        if (p && typeof p.then === 'function') {
          // 异步值,使用第一个触发then的
          p.then(resolve, reject)
        } else {
          // 普通值,直接获取结果
          resolve(p)
        }
      }
    })
  }

#any

批处理 promise,返回一个 Promise 实例,里面值为最快成功的值 返回第一个成功结果,全部失败才返回失败

static any(promises) {
  const rejectedArr=new Array(promises.length)

    return new myPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        const p = promises[i]

        if (p && typeof p.then === 'function') {
          // 异步值,使用第一个成功的,失败的存到数组直到全部失败则返回
          p.then(resolve,reason=>{
            rejectedArr[i]=reason
            if(rejectedArr.length===promises.length){
              reject(rejectedArr)
            }
          })
        } else {
          // 普通值,直接获取结果
          resolve(p)
        }
      }
    })
  }

#参考资料

掘金

23.12.19