返回

ES6 的 Promise 实现:亲手打造异步编程利器

前端

在现代 Web 开发中,异步编程已经成为不可或缺的一部分。而 Promise,作为 JavaScript 中强大的异步编程工具,更是让开发者们如虎添翼。Promise 能够简化异步操作,让代码更具可读性和可维护性。但你知道 Promise 是如何实现的吗?

在本文中,我们将通过 65 行代码,手把手教你实现一个简化版的 ES6 Promise。通过这个过程,你将深入了解 Promise 的工作原理,以及如何使用它来编写更优美的异步代码。

理解 Promise 的基本原理

Promise 的核心思想很简单:它是一个对象,代表着一个异步操作的最终完成或失败的结果。你可以通过 then 方法来注册回调函数,以便在异步操作完成后执行。

Promise 有三种状态:

  • Pending: 异步操作尚未完成。
  • Fulfilled: 异步操作已成功完成。
  • Rejected: 异步操作已失败。

实现我们的简化版 Promise

现在,让我们一步一步地实现我们的简化版 Promise。

1. 定义 Promise 构造函数

function Promise(executor) {
  this.state = "pending";
  this.result = undefined;
  this.onFulfilledCallbacks = [];
  this.onRejectedCallbacks = [];

  const resolve = (result) => {
    if (this.state !== "pending") return;

    this.state = "fulfilled";
    this.result = result;
    this.onFulfilledCallbacks.forEach((callback) => callback(result));
  };

  const reject = (error) => {
    if (this.state !== "pending") return;

    this.state = "rejected";
    this.result = error;
    this.onRejectedCallbacks.forEach((callback) => callback(error));
  };

  executor(resolve, reject);
}

2. 定义 then 方法

Promise.prototype.then = function (onFulfilled, onRejected) {
  return new Promise((resolve, reject) => {
    if (this.state === "fulfilled") {
      setTimeout(() => {
        try {
          const result = onFulfilled(this.result);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      }, 0);
    } else if (this.state === "rejected") {
      setTimeout(() => {
        try {
          const result = onRejected(this.result);
          resolve(result);
        } catch (error) {
          reject(error);
        }
      }, 0);
    } else {
      this.onFulfilledCallbacks.push(() => {
        setTimeout(() => {
          try {
            const result = onFulfilled(this.result);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      });

      this.onRejectedCallbacks.push(() => {
        setTimeout(() => {
          try {
            const result = onRejected(this.result);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      });
    }
  });
};

3. 定义 catch 方法

Promise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected);
};

4. 定义 resolvereject 方法

const resolvePromise = (promise, x, resolve, reject) => {
  if (promise === x) {
    reject(new TypeError("Chaining cycle detected for promise"));
  } else if (x instanceof Promise) {
    x.then(
      (result) => resolvePromise(promise, result, resolve, reject),
      (error) => reject(error)
    );
  } else if (x !== null && (typeof x === "object" || typeof x === "function")) {
    let then;
    try {
      then = x.then;
    } catch (error) {
      reject(error);
    }

    if (typeof then === "function") {
      let called = false;
      try {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            resolvePromise(promise, y, resolve, reject);
          },
          (error) => {
            if (called) return;
            called = true;
            reject(error);
          }
        );
      } catch (error) {
        if (called) return;
        called = true;
        reject(error);
      }
    } else {
      resolve(x);
    }
  } else {
    resolve(x);
  }
};

const resolve = (value) => {
  return new Promise((resolve, reject) => {
    resolvePromise(this, value, resolve, reject);
  });
};

const reject = (reason) => {
  return new Promise((resolve, reject) => {
    reject(reason);
  });
};

5. 测试我们的简化版 Promise

现在,我们已经实现了我们的简化版 Promise,让我们来测试一下它是否正常工作。

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Hello, Promise!");
  }, 1000);
});

promise
  .then((result) => {
    console.log(result); // 输出:"Hello, Promise!"
  })
  .catch((error) => {
    console.log(error);
  });

运行这段代码,你应该会在控制台看到 "Hello, Promise!"。这表明我们的简化版 Promise 能够正常工作。

总结

通过这篇教程,我们一步一步地实现了 ES6 的 Promise。在这个过程中,我们深入了解了 Promise 的工作原理,以及如何使用它来编写更优美的异步代码。我希望这篇文章能够帮助你更好地理解和使用 Promise。