返回

用 JavaScript 手写 Promise

前端

Promise 的实现原理

Promise 在现代 JavaScript 中扮演着至关重要的角色,它提供了一种处理异步操作的优雅方式。本文将深入探讨 Promise 的实现原理,并通过手写一个简单的 Promise 来增强我们的理解。

JavaScript 中的 Promise

Promise 是一个对象,它代表着将来可能完成(或失败)的异步操作的结果。它提供了对异步操作的结果进行处理的方法,消除了回调的嵌套和异步编程的复杂性。

Promise 的状态

Promise 有三种可能的状态:

  • 等待(pending): Promise 尚未完成,操作仍在进行中。
  • 已完成(fulfilled): 操作已成功完成,Promise 持有结果。
  • 已拒绝(rejected): 操作已失败,Promise 持有失败的原因。

Promise 实现

以下步骤展示了如何使用 JavaScript 手写一个简单的 Promise:

  1. 构造函数: Promise 通过构造函数创建,接收一个执行器函数作为参数。执行器函数有两个参数:resolvereject
function MyPromise(executor) {
  // Promise 的当前状态
  this.state = 'pending';

  // Promise 完成时存储的结果
  this.result = undefined;

  // Promise 失败时存储的错误
  this.error = undefined;

  // 存储等待状态解决的回调
  this.onFulfilledCallbacks = [];
  this.onRejectedCallbacks = [];

  // 立即执行执行器函数
  executor(resolve.bind(this), reject.bind(this));
}
  1. resolve 函数: resolve 函数用于将 Promise 的状态从等待变为已完成,并存储操作的结果。
function resolve(result) {
  // 检查 Promise 状态是否为等待
  if (this.state !== 'pending') {
    return;
  }

  // 将 Promise 状态更新为已完成
  this.state = 'fulfilled';

  // 将结果存储在 Promise 中
  this.result = result;

  // 调用所有等待状态解决的回调
  this.onFulfilledCallbacks.forEach(callback => callback(result));
}
  1. reject 函数: reject 函数用于将 Promise 的状态从等待变为已拒绝,并存储操作失败的原因。
function reject(error) {
  // 检查 Promise 状态是否为等待
  if (this.state !== 'pending') {
    return;
  }

  // 将 Promise 状态更新为已拒绝
  this.state = 'rejected';

  // 将错误存储在 Promise 中
  this.error = error;

  // 调用所有等待状态解决的回调
  this.onRejectedCallbacks.forEach(callback => callback(error));
}
  1. then 方法: then 方法用于在 Promise 完成或失败时添加回调。它返回一个新的 Promise,该 Promise 的结果取决于原始 Promise 的状态。
MyPromise.prototype.then = function (onFulfilled, onRejected) {
  // 创建一个新的 Promise
  const newPromise = new MyPromise();

  // 检查原始 Promise 的状态
  if (this.state === 'fulfilled') {
    // 如果已完成,则立即调用 onFulfilled 回调
    onFulfilled(this.result);
  } else if (this.state === 'rejected') {
    // 如果已拒绝,则立即调用 onRejected 回调
    onRejected(this.error);
  } else {
    // 如果仍处于等待状态,则将回调添加到队列中
    this.onFulfilledCallbacks.push(onFulfilled);
    this.onRejectedCallbacks.push(onRejected);
  }

  return newPromise;
};

实际应用

使用我们的手写 Promise,我们可以异步地获取用户输入:

const getUserInput = () => {
  return new MyPromise((resolve, reject) => {
    setTimeout(() => {
      // 模拟获取用户输入
      const input = 'Hello, world!';

      // 操作成功,调用 resolve 传递结果
      resolve(input);
    }, 2000);
  });
};

getUserInput().then(result => {
  console.log(`用户输入:${result}`);
}).catch(error => {
  console.error(`获取用户输入失败:${error}`);
});

结论

通过手写一个 Promise,我们深入了解了 Promise 的实现原理和它在处理异步操作中的作用。这种理解对于掌握现代 JavaScript 编程至关重要,因为它使我们能够构建更健壮、更可维护的代码。