手写 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 有所帮助。

相关推荐
崔庆才丨静觅15 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606116 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了16 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅16 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅16 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅17 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment17 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅17 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊17 小时前
jwt介绍
前端