首页  >  文章  >  web前端  >  构建 XPromise:深入研究自定义 JavaScript Promise

构建 XPromise:深入研究自定义 JavaScript Promise

Linda Hamilton
Linda Hamilton原创
2024-10-26 13:40:03725浏览

JavaScript 以其异步特性而闻名,可以在不阻塞其他进程的情况下实现数据获取、动画和文件处理等操作。 Promise 是优雅地处理异步操作的核心,使我们的代码更干净、更易于管理。这个项目 XPromise 是 JavaScript Promise 的自定义实现,帮助我们探索 Promise 机制的内部工作原理。

您可以在 GitHub 上查看完整的实现。

什么是承诺?

JavaScript 中的 Promise 是一个特殊的对象,表示异步操作的最终完成或失败。使用 Promises,我们可以将操作排队以在任务完成后运行,即使我们不知道任务何时完成。以下是 Promise 的独特之处:

  1. 三种状态:Promise 可以是 待处理已履行已拒绝
  2. 不可变的状态变化:一旦 Promise 被解决(履行或拒绝),它就无法更改状态。
  3. 与 .then 和 .catch 链接:Promise 提供 .then() 来处理已实现的值,并提供 .catch() 来处理错误,使它们可组合。

Building XPromise: A Deep Dive into Custom JavaScript Promises

为什么要建立自定义承诺?

创建自定义 Promise,如 XPromise,可以更深入地了解其内部工作原理:

  • 状态管理:我们以确保只有一个最终状态的方式处理状态。
  • 回调队列:Promise 必须将回调排队,以便在解析后执行。
  • 错误处理:它包括一种优雅地处理异步错误的方法,模拟原生 Promise 行为。

项目演练

让我们浏览一下 XPromise 的代码,探索使其像 JavaScript 的原生 Promises 一样工作的每个组件。

设置状态和基本结构

XPromise 首先定义三种状态:PENDING、FULFILLED 和 REJECTED。

const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";

class XPromise {
  constructor(executor) {
    this.state = PENDING;
    this.queue = [];
    doResolve(this, executor);
  }
  // ...
}
  1. 构造函数和初始设置
    • XPromise 接受一个执行器函数,该函数会立即运行。
    • this.state 跟踪当前状态,而 this.queue 保存通过 .then() 调用排队的所有函数。

添加 then、catch 和finally 方法

通过then、catch和finally,我们处理完成、拒绝和清理场景。 XPromise 实现链接的方式如下:

const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";

class XPromise {
  constructor(executor) {
    this.state = PENDING;
    this.queue = [];
    doResolve(this, executor);
  }
  // ...
}
  1. then:then 方法创建一个新的 XPromise 实例并将其与 onFulfilled 和 onRejected 回调一起存储。这确保链中的下一个 Promise 接收前一个 Promise 的输出。
  2. catch:处理错误的简写,相当于调用 then(null, onRejected)。
  3. finally:处理无论 Promise 结果如何都会执行的清理操作。

使用句柄管理已解决的状态

handle 函数决定 Promise 是否仍待处理或已解决。如果它处于待处理状态,则处理程序将添加到队列中以供稍后执行。如果 Promise 得到解决,它会立即处理处理程序。

then(onFulfilled, onRejected) {
  const promise = new XPromise(() => {});
  handle(this, { promise, onFulfilled, onRejected });
  return promise;
}

catch(onRejected) {
  return this.then(null, onRejected);
}

finally(onFinally) {
  return this.then(onFinally, onFinally);
}

解决和拒绝承诺

履行和拒绝的 Promise 需要特殊的函数来处理其结果。 XPromise 是如何实现这一目标的:

function handle(promise, handler) {
  while (promise.state !== REJECTED && promise.value instanceof XPromise) {
    promise = promise.value;
  }

  if (promise.state === PENDING) {
    promise.queue.push(handler);
  } else {
    handleResolved(promise, handler);
  }
}
  1. 履行和拒绝

    • 履行和拒绝最终确定 Promise,更新其状态和值。
    • 如果 value 是 Promise 或 thenable,我们会推迟 doResolve 以确保它得到正确处理。
  2. 完成排队处理程序:

    • 一旦 Promise 得到解决,finale 就会遍历队列以按顺序执行所有处理程序。

执行器函数 doResolve

doResolve 函数通过包装解析和拒绝调用来安全地运行执行器,防止多次调用它们时发生任何进一步的状态更改。

function fulfill(promise, value) {
  if (value === promise) {
    return reject(promise, new TypeError());
  }

  if (value && (typeof value === "object" || typeof value === "function")) {
    let then;
    try {
      then = value.then;
    } catch (e) {
      return reject(promise, e);
    }

    if (typeof then === "function") {
      return doResolve(promise, then.bind(value));
    }
  }

  promise.state = FULFILLED;
  promise.value = value;
  finale(promise);
}

function reject(promise, reason) {
  promise.state = REJECTED;
  promise.value = reason;
  finale(promise);
}

XPromise 的用法示例

现在我们有了一个可以运行的 XPromise,让我们用一个简单的例子来尝试一下:

function doResolve(promise, executor) {
  let called = false;
  function wrapFulfill(value) {
    if (called) return;
    called = true;
    fulfill(promise, value);
  }

  function wrapReject(reason) {
    if (called) return;
    called = true;
    reject(promise, reason);
  }
  try {
    executor(wrapFulfill, wrapReject);
  } catch (e) {
    wrapReject(e);
  }
}

要点

从头开始重新实现 Promise 提供了有关如何在 JavaScript 中管理异步编程的实践见解:

  • 状态管理确保Promise仅解决一次,保持履行或拒绝。
  • 回调队列允许有效处理多个链式.then()调用。
  • 错误处理使用catch,最终有助于优雅地处理异步错误。

要深入了解代码,请查看 GitHub 上的 XPromise 项目。试验代码并随意自定义它以探索更高级的功能,例如 Promise 竞争条件、链接和嵌套!

以上是构建 XPromise:深入研究自定义 JavaScript Promise的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn