手撕Promise【带注释详解】

文章详细介绍了如何从零开始实现一个简单的Promise类,包括构造函数、resolve和reject方法,以及then、catch和finally方法的实现。它涉及到Promise的状态管理,处理thenable对象,以及异步回调的执行策略。此外,还包含了Promise的静态方法如resolve、reject、all和race的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

class MyPromise {
  constructor(executor) {
    this.status = 'pending'; // 初始状态为 pending
    this.value = undefined; // Promise 的结果值
    this.error = undefined; // Promise 的错误信息
    this.onFulfilledCallbacks = []; // 存储 Promise 成功状态下的回调函数
    this.onRejectedCallbacks = []; // 存储 Promise 失败状态下的回调函数

    // 成功时执行的函数
    const resolve = (value) => {
      if (this.status === 'pending') {
        if (value instanceof MyPromise) {
          // 如果 value 的值是一个 Promise 对象,等其状态改变后再执行
          value.then(resolve, reject);
        }
      }
      if (isThenable(value)) {
        // 如果 value 是一个 thenable 对象,那么就先把它转为 Promise 对象,然后等待它的状态改变
        return handleThenable(value, resolve, reject);
      }
      this.status = 'fulfilled'; // 状态改变为 fulfilled
      this.value = value; // 保存结果值
      this.executeCallbacks(this.onFulfilledCallbacks); // 执行回调函数
    }
    // 失败时执行的函数
    const reject = (error) => {
      if (this.status === 'pending') {
        this.status = 'rejected'; // 状态改变为 rejected
        this.error = error; // 保存错误信息
        this.executeCallbacks(this.onRejectedCallbacks); // 依次执行失败状态下的回调函数
      }
    }

    try {
      executor(resolve, reject); // 执行执行器函数,并传入 resolve 和 reject 函数作为参数
    } catch (error) {
      reject(error); // 捕获执行器函数中的错误,并将 Promise 状态改为 rejected
    }

  }
  executeCallbacks(callbacks) {
    callbacks.forEach((callback) => {
      /*
      * 为什么要使用 setTimeout 呢?
      * 
      * 因为js的代码执行是基于时间循环的。当执行到一个宏任务(例如执行函数、网络请求等)时,会先执行当前任务的同步代码,然后再执行微任务队列中的任务。
      * 在微任务队列中的任务执行完毕后,才会执行下一个宏任务。
      * 
      * 而使用 setTimeout 时,会将函数的执行放到下一个宏任务中执行。将毁掉函数放入延时定时器中,设置为0秒的延时,实际上是将其放到了下一个宏任务中执行。
      * 这样做的目的是为了确保当前的同步代码执行完毕,让js引擎有机会执行微任务队列中的任务,比米娜阻塞时间循环。
      * 
      * 而在 executeCallbacks 函数中,我们是通过forEach遍历回调函数并执行的。使用延时定时器是为了将回调函数放到下一个宏任务中执行,确保当前Promise的状态已经改变,从而
      * 能够正确的执行回调函数。
      * 
      * */
      setTimeout(() => {
        try {
          const result = callback(this.value);
          if (result === this) {
            // 如果回调函数返回的值是当前 Promise 对象,那么就会陷入死循环,这时需要抛出错误
            throw new TypeError('Chaining cycle detected for promise #<Promise>');
          }
          if (isThenable(result)) {
            // 如果回调函数返回的是一个 thenable 对象,那么就先把它转为 Promise 对象,然后等待它的状态改变
            handleThenable(result, resolve, reject);
          } else {
            // 否则就是返回的是一个普通值,那么就用该值直接调用 resolve 函数,解析结果
            resolve(result);
          }
        } catch (error) {
          // 如果回调函数执行时抛出了异常,那么就用该异常对象调用 reject 函数,并将 Promise 状态改为 rejected
          reject(error);
        }
      }, 0)
    })
  }
  // then 方法
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value; // 如果 onFulfilled 不是函数,则将其设置为一个返回 value 的函数
    onRejected = typeof onRejected === 'function' ? onRejected : (error) => { throw error }; // 如果 onRejected 不是函数,则将其设置为一个抛出 error 的函数
    /*
     * 
     * 每次调用 then 方法都会生成一个新的Promise对象,而不是修改原是的Promise对象。这时Promise链式调用的特性,保证了每个Promise对象的状态都是独立的,互不影响。
     * 
     */
    return new MyPromise((resolve, reject)=>{
      const fulfilledHandler = () => {
        setTimeout(() => {
          try {
            // 如果 onFulfilled 返回的是一个 thenable 对象,那么就先把它转为 Promise 对象,然后等待它的状态改变
            const result = onFulfilled(this.value);
            if (isThenable(result)) {
              handleThenable(result, resolve, reject); // 如果 onFulfilled 返回的是一个 thenable 对象,那么就先把它转为 Promise 对象,然后等待它的状态改变
            } else {
              resolve(result); // 否则就是返回的是一个普通值,那么就用该值直接调用 resolve 函数,解析结果
            }
          } catch (error) {
            reject(error); // 如果 onFulfilled 执行时抛出了异常,那么就用该异常对象调用 reject 函数,并将 Promise 状态改为 rejected
          }
        }, 0)
      }
      const rejectedHandler = () => {
        setTimeout(() => {
          try {
            const result = onRejected(this.error); // 如果 onRejected 执行时抛出了异常,那么就用该异常对象调用 reject 函数,并将 Promise 状态改为 rejected
            if (isThenable(result)) {
              handleThenable(result, resolve, reject); // 如果 onRejected 返回的是一个 thenable 对象,那么就先把它转为 Promise 对象,然后等待它的状态改变
            } else {
              resolve(result); // 否则就是返回的是一个普通值,那么就用该值直接调用 resolve 函数,解析结果
            }
          } catch (error) {
            reject(error); // 如果 onRejected 执行时抛出了异常,那么就用该异常对象调用 reject 函数,并将 Promise 状态改为 rejected
          }
        }, 0)
      }

      if (this.status === 'fulfilled') {
        fulfilledHandler(); // 如果当前 Promise 的状态是 fulfilled,那么就执行 onFulfilled 函数
      } else if (this.status === 'rejected') {
        rejectedHandler(); // 如果当前 Promise 的状态是 rejected,那么就执行 onRejected 函数
      } else {
        this.onFulfilledCallbacks.push(fulfilledHandler); // 存储成功状态下的回调函数
        this.onRejectedCallbacks.push(rejectedHandler); // 存储失败状态下的回调函数
      }
    })
  }
  // catch 方法
  catch(onRejected) {
    return this.then(undefined, onRejected); // 指定失败回调函数
  }
  // finally 方法
  finally(onFinally) {
    return this.then(
      (value) => MyPromise.resolve(onFinally()).then(() => value), // 执行 finally 回调函数后,继续返回 Promise 的值
      (error) => MyPromise.resolve(onFinally()).then(() => { throw error }) // 执行 finally 回调函数后,继续抛出错误
    )
  }
  // 静态 resolve 方法
  static resolve(value) {
    // 如果参数是 Promise 实例,那么直接返回这个实例
    if (value instanceof MyPromise) {
      return value; // 如果参数是 Promise 实例,那么直接返回这个实例
    }
    // 如果参数是 thenable 对象,那么就先将其转为 Promise 对象,然后等待它的状态改变
    if (isThenable(value)) {
      return new MyPromise((resolve, reject) => {
        handleThenable(value, resolve, reject); // 如果参数是 thenable 对象,那么就先将其转为 Promise 对象,然后等待它的状态改变
      })
    }
    return new MyPromise((resolve) => resolve(value)); // 如果参数是普通值,那么直接返回以该值为成功状态的 Promise 对象
  }
  // 静态 reject 方法
  static reject(error) {
    return new MyPromise((resolve, reject) => reject(error)); // 直接返回以该错误对象为失败状态的 Promise 对象
  }
  // 静态 all 方法
  static all(promises) {
    return new MyPromise((resolve, reject) => {

      const results = []; // 存储所有 Promise 的结果
      let completedCound = 0; // 记录已经完成的 Promise 的数量

      const checkCompletion = () => {
        if (completedCound === promises.length) {
          resolve(results); // 当所有 Promise 都完成时,调用 resolve 函数
        }
      }

      // 遍历所有 Promise
      promises.forEach((promises, index) => {
        // 如果当前 Promise 的状态是 fulfilled,那么就将其结果存入 result 数组中
        promises.then((value) => {
          results[index] = value; // 将 Promise 的结果存入 result 数组中
          completedCound++; // 已经完成的 Promise 的数量加 1
          checkCompletion(); // 检查是否所有 Promise 都已经完成
        }).catch((error) => {
          reject(error); // 如果有任何一个 Promise 失败,则将错误信息传递给 reject 函数
        })
      })
    })
  }
  // 静态race方法
  static race(promises) {
    return new MyPromise((resolve, reject)=>{
      // 遍历所有 Promise
      promises.forEach((promise)=>{
        // 如果当前 Promise 的状态是 fulfilled,那么就将其结果存入 result 数组中
        promise.then((value)=>{
          resolve(value); // 如果有任何一个 Promise 成功,则将其结果传递给 resolve 函数
        }).catch((error)=>{
          reject(error); // 如果有任何一个 Promise 失败,则将错误信息传递给 reject 函数
        })
      })
    })
  }
}
// 判断一个对象是否是 thenable 对象
function isThenable(value) {
  return value && typeof value.then === 'function'; // 判断一个对象是否是 thenable 对象
}
// 处理 thenable 对象
function handleThenable(thenable, resolve, reject) {
  try {
    thenable.then(resolve, reject); // 如果参数是 thenable 对象,那么就先将其转为 Promise 对象,然后等待它的状态改变
  } catch (error) {
    reject(error); // 如果在处理过程中出现错误,则将错误信息传递给 reject 函数
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZemanZhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值