返回

剖析 Promise 源码,五分钟教你实现异步编程利器

前端

掌握 Promise,即可轻松实现异步编程,告别回调函数的繁杂,尽享代码简洁之美。

Promise 是 JavaScript 中的异步编程利器,它允许我们轻松处理异步操作,让代码更具可读性和可维护性。实现 Promise 并不难,只需五分钟,就能彻底掌握其工作原理。

首先,我们来拆解 Promise 的基本结构:

class Promise {
  constructor(executor) {
    this.state = "pending";
    this.result = undefined;
    this.onResolveCallbacks = [];
    this.onRejectCallbacks = [];

    const resolve = (value) => {
      if (this.state === "pending") {
        this.state = "fulfilled";
        this.result = value;
        this.onResolveCallbacks.forEach((callback) => callback(value));
      }
    };

    const reject = (error) => {
      if (this.state === "pending") {
        this.state = "rejected";
        this.result = error;
        this.onRejectCallbacks.forEach((callback) => callback(error));
      }
    };

    executor(resolve, reject);
  }

  then(onResolve, onReject) {
    return new Promise((resolve, reject) => {
      if (this.state === "fulfilled") {
        onResolve(this.result);
      } else if (this.state === "rejected") {
        onReject(this.result);
      } else {
        this.onResolveCallbacks.push(() => {
          onResolve(this.result);
        });
        this.onRejectCallbacks.push(() => {
          onReject(this.result);
        });
      }
    });
  }

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

  finally(onFinally) {
    return this.then(
      (result) => {
        onFinally();
        return result;
      },
      (error) => {
        onFinally();
        throw error;
      }
    );
  }
}

Promise 的核心在于 stateresult 和三个回调函数数组:onResolveCallbacksonRejectCallbacksfinallyCallbacks

state 属性表示 Promise 的状态,可以是 "pending"、"fulfilled" 或 "rejected"。

result 属性存储 Promise 的结果,当 Promise 被成功解析时,该属性将存储解析值;当 Promise 被拒绝时,该属性将存储拒绝原因。

onResolveCallbacksonRejectCallbacksfinallyCallbacks 数组分别存储当 Promise 被解析、被拒绝或执行 finally 时要调用的回调函数。

Promise 提供了 then()catch()finally() 三个方法:

  • then() 方法接受两个参数,第一个参数是当 Promise 被解析时要调用的回调函数,第二个参数是当 Promise 被拒绝时要调用的回调函数。
  • catch() 方法接受一个参数,是当 Promise 被拒绝时要调用的回调函数。
  • finally() 方法接受一个参数,是当 Promise 被解析或被拒绝时都要调用的回调函数。

现在,让我们一步一步实现属于自己的 Promise:

function myPromise(executor) {
  let state = "pending";
  let result;
  const callbacks = [];

  const resolve = (value) => {
    if (state === "pending") {
      state = "fulfilled";
      result = value;
      callbacks.forEach((callback) => callback(value));
    }
  };

  const reject = (error) => {
    if (state === "pending") {
      state = "rejected";
      result = error;
      callbacks.forEach((callback) => callback(error));
    }
  };

  executor(resolve, reject);

  return {
    then(callback) {
      return new myPromise((resolve, reject) => {
        if (state === "fulfilled") {
          resolve(callback(result));
        } else if (state === "rejected") {
          reject(callback(result));
        } else {
          callbacks.push(() => {
            resolve(callback(result));
          });
        }
      });
    },

    catch(callback) {
      return new myPromise((resolve, reject) => {
        if (state === "rejected") {
          resolve(callback(result));
        } else if (state === "fulfilled") {
          reject(callback(result));
        } else {
          callbacks.push(() => {
            resolve(callback(result));
          });
        }
      });
    },

    finally(callback) {
      return new myPromise((resolve, reject) => {
        if (state === "fulfilled") {
          resolve(callback());
        } else if (state === "rejected") {
          reject(callback());
        } else {
          callbacks.push(() => {
            resolve(callback());
          });
        }
      });
    }
  };
}

这个简单的实现足以让我们掌握 Promise 的基本原理。我们可以使用它来实现一些实用的功能,例如:

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

promise.then((result) => {
  console.log(result); // "Hello, world!"
});

这个代码创建一个 Promise,并在 1 秒后解析它。然后,我们使用 then() 方法来处理解析结果。

这就是 Promise 的基本原理。只要掌握了这些基础知识,我们就可以轻松实现异步编程,让我们的代码更具可读性和可维护性。