手写 Promise:深入理解异步编程

手写 Promise:深入理解异步编程

在现代 JavaScript 中,Promise 是一种用于处理异步操作的重要工具。通过手写实现一个简单的 Promise 类,我们能更深入地理解 Promise 的工作原理和异步编程的机制。在这篇博客中,我们将逐步构建一个功能齐全的 Promise 类,包括基本结构、then 方法、静态方法如 resolverejectallallSettledraceany,以及一些辅助方法。

Promise 的基本结构

首先,我们定义一个 MyPromise 类,其中包含常见的 Promise 状态和基本结构:

javascript 复制代码
class MyPromise {
  static REJECTED = 'rejected';
  static PENDING = 'pending';
  static FULFILLED = 'fulfilled';

  value = undefined;
  status = MyPromise.PENDING;
  onFulfilledCallBacks = [];
  onRejectedCallBacks = [];

  constructor(execute) {
    const resolve = (value) => {
      if (this.status === MyPromise.PENDING) {
        this.value = value;
        this.status = MyPromise.FULFILLED;
        this.onFulfilledCallBacks.forEach((func) => func(value));
      }
    };

    const reject = (value) => {
      if (this.status === MyPromise.PENDING) {
        this.value = value;
        this.status = MyPromise.REJECTED;
        this.onRejectedCallBacks.forEach((func) => func(value));
      }
    };

    try {
      execute(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }
  // ...(后续实现)
}

这里定义了 MyPromise 类的基本结构,包括状态常量、初始值、状态和执行回调数组等。

实现 then 方法

then 方法是 Promise 的核心,它用于注册在 Promise 完成时执行的回调函数。以下是 then 方法的基本实现:

javascript 复制代码
then(onFulfilled, onRejected) {
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (onFulfilled) => onFulfilled;
  onRejected = typeof onRejected === 'function' ? onRejected : (onRejected) => onRejected;

  return new MyPromise((resolve, reject) => {
    // 处理已完成状态
    if (this.status === MyPromise.FULFILLED) {
      try {
        queueMicrotask(() => {
          const result = onFulfilled(this.value);
          this.handlePromiseResult(result, resolve, reject);
        });
      } catch (error) {
        reject(error);
      }
    }
    // 处理已拒绝状态
    else if (this.status === MyPromise.REJECTED) {
      try {
        queueMicrotask(() => {
          const result = onRejected(this.value);
          this.handlePromiseResult(result, resolve, reject);
        });
      } catch (error) {
        reject(error);
      }
    }
    // 处理异步状态
    else {
      this.onFulfilledCallBacks.push((value) => {
        queueMicrotask(() => {
          const result = onFulfilled(value);
          this.handlePromiseResult(result, resolve, reject);
        });
      });
      this.onRejectedCallBacks.push((value) => {
        queueMicrotask(() => {
          const result = onRejected(value);
          this.handlePromiseResult(result, resolve, reject);
        });
      });
    }
  });
}

handlePromiseResult(result, resolve, reject) {
  if (result instanceof MyPromise) {
    result.then(resolve, reject);
  } else {
    resolve(result);
  }
}

then 方法中,我们判断当前 Promise 的状态,根据状态的不同执行相应的回调函数。如果是异步状态,则将回调函数推入对应的回调数组中,等待状态改变时执行。

实现 resolvereject 静态方法

resolverejectMyPromise 类的两个静态方法,用于创建已解决或已拒绝的 Promise。以下是它们的实现:

javascript 复制代码
static resolve = (value) => {
  return new MyPromise((resolve, reject) => {
    resolve(value);
  });
};

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

这两个方法分别返回一个已解决或已拒绝的 Promise。

all 方法

all 方法接收一个 Promise 数组,返回一个新的 Promise。只有当所有输入的 Promise 都解决时,新 Promise 才会解决,并返回包含所有 Promise 结果的数组;否则,只要有一个 Promise 拒绝,新 Promise 就会被拒绝。

javascript 复制代码
static all = (promises) => {
  if (!this._hasIterator(promises)) {
    throw new Error('参数不可迭代');
  }

  return new MyPromise((resolve, reject) => {
    const resultArr = [];
    promises.forEach((promise) => {
      promise.then(
        (res) => {
          if (resultArr.length === promises.length) {
            resolve(resultArr);
          }
          resultArr.push(res);
        },
        (err) => {
          reject(err);
        }
      );
    });
  });
};

实现 allSettledraceany 方法

allSettled 方法返回一个 Promise,该 Promise 在所有给定的 Promise 都已经解决或拒绝后解决。它会等待所有的 Promise 完成,无论成功还是失败,并返回一个包含每个 Promise 结果的数组。

javascript 复制代码
static allSettled = (promises) => {
  if (!this._hasIterator(promises)) {
    throw new Error('参数不可迭代');
  }

  return new MyPromise((resolve) => {
    const resultArr = [];
    promises.forEach((promise, index) => {
      promise.then(
        (res) => {
          resultArr.push({ status: 'fulfilled', value: res });
          if (resultArr.length === promises.length) {
            resolve(resultArr);
          }
        },
        (res) => {
          resultArr.push({ status: 'rejected', reason: res });
          if (resultArr.length === promises.length) {
            resolve(resultArr);
          }
        }
      );
    });
  });
};

race 方法返回一个 Promise,该 Promise 在给定的任意 Promise 解决或拒绝后立即解决。

javascript 复制代码
static race = (promises) => {
  if (!this._hasIterator(promises)) {
    throw new Error('参数不可迭代');
  }

  return new MyPromise((resolve, reject) => {
    promises.forEach((promise) => {
      promise.then(
        (res) => {
          resolve(res);
        },
        (res) => {
          reject(res);
        }
      );
    });
  });
};

any 方法返回一个 Promise,该 Promise 在给定的任意 Promise 解决后立即解决。与 race 不同的是,any 只要有一个 Promise 解决即可,不管其状态是成功还是失败。

javascript 复制代码
static any = (promises) => {
  if (!this._hasIterator(promises)) {
    throw new Error('参数不可迭代');
  }

  return new MyPromise((resolve, reject) => {
    promises.forEach((promise) => {
      promise.then((res) => {
        resolve(res);
      });
    });
  });
};

辅助方法:deferred

为了方便创建一个延迟解决的 Promise 对象,我们添加了 deferred 方法:

javascript 复制代码
static deferred = () => {
  let dfd = {};
  dfd.promise = new MyPromise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject;
  });
  return dfd;
};

这个方法返回一个包含 promiseresolvereject 的对象,方便后续使用。

总结

通过以上的实现,我们成功地创建了一个简单但功能齐全的 Promise 类。这个手写 Promise 不仅具备基本的异步操作能力,还支持 Promise 链式调用和常见的 Promise 方法,如 thenresolverejectallallSettledraceany

手写实现 Promise 是一个有挑战性但也有益处的练习,有助于更深入地理解 Promise 的工作原理和异步编程的机制。希望这篇博客对你理解 Promise 有所帮助。

相关推荐
xiaohe06012 分钟前
💘 霸道女总裁爱上前端开发的我
前端·游戏开发·trae
sophie旭5 分钟前
内存泄露排查之我的微感受
前端·javascript·性能优化
k***19513 分钟前
Spring 核心技术解析【纯干货版】- Ⅶ:Spring 切面编程模块 Spring-Instrument 模块精讲
前端·数据库·spring
努力学算法的蒟蒻40 分钟前
day58(1.9)——leetcode面试经典150
算法·leetcode·面试
rgeshfgreh1 小时前
Spring事务传播机制深度解析
java·前端·数据库
Hilaku1 小时前
我用 Gemini 3 Pro 手搓了一个并发邮件群发神器(附源码)
前端·javascript·github
IT_陈寒1 小时前
Java性能调优实战:5个被低估却提升30%效率的JVM参数
前端·人工智能·后端
快手技术2 小时前
AAAI 2026|全面发力!快手斩获 3 篇 Oral,12 篇论文入选!
前端·后端·算法
UrbanJazzerati2 小时前
统计学的"测谎仪":一文搞懂方差、标准差与“N-1”的秘密
面试
颜酱2 小时前
前端算法必备:滑动窗口从入门到很熟练(最长/最短/计数三大类型)
前端·后端·算法