返回

Promise 的实践指南:从头开始实现它的全部功能

前端

了解 Promise 的奥秘:亲自动手实现它的强大功能

引言

Promise 是 JavaScript 中异步编程的基石,它简化了异步操作的处理,让开发者可以轻松处理复杂的异步逻辑。虽然有许多库和框架提供了开箱即用的 Promise 实现,但亲自动手实现 Promise 对于深入理解其工作原理和掌握异步编程至关重要。本文将带领您一步一步地实现 Promise 的所有方法,揭示其背后的魔力。

什么是 Promise?

Promise 是一个表示异步操作的最终结果的对象。它可以处于三种状态:

  • Pending: 操作正在进行中。
  • Fulfilled: 操作已成功完成。
  • Rejected: 操作已失败。

实现 Promise

实现 Promise 涉及创建和管理三个核心方法:

  • constructor :创建一个新的 Promise 对象。
  • then :添加回调函数以处理 Promise 的结果。
  • catch :添加回调函数以处理 Promise 的拒绝。

constructor

constructor 方法使用以下语法创建新的 Promise 对象:

const promise = new Promise((resolve, reject) => {});
  • resolve 函数用于将 Promise 标记为已完成并提供结果值。
  • reject 函数用于将 Promise 标记为已拒绝并提供错误值。

then

then 方法用于添加回调函数来处理 Promise 的结果:

promise.then((result) => {
  // 成功回调:处理已完成的 Promise。
});
  • 成功回调函数接收 Promise 的结果作为参数。

catch

catch 方法用于添加回调函数来处理 Promise 的拒绝:

promise.catch((error) => {
  // 拒绝回调:处理已拒绝的 Promise。
});
  • 拒绝回调函数接收 Promise 的错误值作为参数。

Promise 链

Promise 可以链接在一起形成链,以便轻松处理多个异步操作的顺序执行:

promise1
  .then((result1) => promise2(result1))
  .then((result2) => promise3(result2))
  .catch((error) => {
    // 处理任何 Promise 拒绝。
  });

实践示例

考虑一个示例,其中我们将实现一个 Promise,该 Promise 以异步方式获取用户的年龄:

const getAge = (userId) => {
  return new Promise((resolve, reject) => {
    // 模拟异步操作。
    setTimeout(() => {
      const age = Math.floor(Math.random() * 100);
      resolve(age);
    }, 1000);
  });
};

使用示例

getAge(1)
  .then((age) => {
    console.log(`用户年龄:${age}`);
  })
  .catch((error) => {
    console.log(`错误:${error}`);
  });

完整实现

以下是最完整的 Promise 实现:

class Promise {
  constructor(executor) {
    this.state = "pending";
    this.result = undefined;
    this.error = undefined;
    this.successCallbacks = [];
    this.failureCallbacks = [];

    const resolve = (result) => {
      if (this.state !== "pending") return;
      this.state = "fulfilled";
      this.result = result;
      this.successCallbacks.forEach((callback) => callback(result));
    };

    const reject = (error) => {
      if (this.state !== "pending") return;
      this.state = "rejected";
      this.error = error;
      this.failureCallbacks.forEach((callback) => callback(error));
    };

    executor(resolve, reject);
  }

  then(successCallback, failureCallback) {
    if (this.state === "fulfilled") {
      successCallback(this.result);
    } else if (this.state === "rejected") {
      failureCallback(this.error);
    } else {
      this.successCallbacks.push(successCallback);
      this.failureCallbacks.push(failureCallback);
    }
  }

  catch(failureCallback) {
    this.then(null, failureCallback);
  }
}