返回

深入浅出自制 Promise

前端

纵观 JavaScript 的发展史,Promise 的出现可谓是一次划时代的革新,它优雅地解决了异步编程中回调地狱的问题。虽然 ES6 仅提供了 Promise A+ 规范,但实际实现却交由各浏览器厂商负责。本文将带领你踏上自制 Promise 的探索之旅,让你亲手领略 Promise 的精妙之处。

为何自制 Promise?

自制 Promise 并非为了替代原生 Promise,而是为了加深对 Promise 原理的理解。通过亲自动手实现,我们可以从底层洞悉 Promise 的工作机制,为后续深入学习和疑难解答奠定坚实的基础。

Promise A+ 规范

在着手自制 Promise 之前,我们必须牢牢把握 Promise A+ 规范。该规范定义了 Promise 的行为准则,包括:

  • 状态变更:Promise 只能从 "pending" 变为 "fulfilled" 或 "rejected"。
  • then 方法:then 方法允许我们对 Promise 的结果进行处理。
  • catch 方法:catch 方法用于处理 Promise 失败的情况。

自制 Promise 实现

下面,我们将逐一实现 Promise A+ 规范中的关键要素:

class Promise {
  constructor(executor) {
    this.state = "pending";
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

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

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

    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error);
    }
  }

  then(onFulfilled, onRejected) {
    return new Promise((resolve, reject) => {
      if (this.state === "fulfilled") {
        const result = onFulfilled(this.value);
        result instanceof Promise ? result.then(resolve, reject) : resolve(result);
      } else if (this.state === "rejected") {
        onRejected(this.reason);
      } else {
        this.onFulfilledCallbacks.push(() => {
          const result = onFulfilled(this.value);
          result instanceof Promise ? result.then(resolve, reject) : resolve(result);
        });
        this.onRejectedCallbacks.push((reason) => onRejected(reason));
      }
    });
  }

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

实践应用

现在,让我们用自制 Promise 编写一个简单的 HTTP 请求函数:

function get(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => {
      if (xhr.status === 200) {
        resolve(xhr.responseText);
      } else {
        reject(new Error(`请求失败:${xhr.status}`));
      }
    };
    xhr.onerror = () => reject(new Error("网络错误"));
    xhr.send();
  });
}

总结

自制 Promise 是一段既有挑战性又有收获的旅程。通过亲自动手实现 Promise A+ 规范,我们不仅加深了对 Promise 原理的理解,还培养了独立解决问题的能力。这种经验对于我们成为一名合格的前端开发者至关重要。