返回

细分思维,手写Promise不再难!

前端

如今,面试越来越内卷,动不动就手写各种源码,其中最让程序员头疼的恐怕就是手写Promise了。很多人一听到这个要求就头大,毫无思路,不知道从哪里下手。

其实,只要我们把功能需求拆封一下,分步骤实现,手写Promise就没有那么难了。

理解Promise

Promise是一个用来处理异步操作的类。它可以让你在执行异步操作后,链式调用一个或多个回调函数。当异步操作完成时,它会把结果或错误信息传递给回调函数。

Promise的结构

Promise类有三个状态:

  • Pending: 异步操作还未开始或正在进行中。
  • Fulfilled: 异步操作已完成且成功。
  • Rejected: 异步操作已完成且失败。

每个Promise对象都有一个内部状态和一个回调函数队列。当Promise的状态发生变化时,它会依次执行回调函数队列中的函数。

如何使用Promise

要使用Promise,你需要创建一个Promise对象,并传入一个执行器函数。执行器函数有两个参数:resolve和reject。resolve用于在异步操作成功时调用,reject用于在异步操作失败时调用。

例如,以下代码演示了如何创建一个Promise对象并使用它:

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() < 0.5) {
      resolve("成功!");
    } else {
      reject("失败!");
    }
  }, 1000);
});

promise.then((result) => {
  console.log(result);
}, (error) => {
  console.log(error);
});

手写Promise

现在,我们来看看如何手写一个Promise类。

首先,我们需要定义一个Promise类:

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

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

  resolve(value) {
    if (this.state !== "pending") {
      return;
    }

    this.state = "fulfilled";
    this.value = value;

    this.onFulfilledCallbacks.forEach((callback) => {
      callback(this.value);
    });
  }

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

    this.state = "rejected";
    this.error = error;

    this.onRejectedCallbacks.forEach((callback) => {
      callback(this.error);
    });
  }

  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== "function") {
      onFulfilled = (value) => value;
    }

    if (typeof onRejected !== "function") {
      onRejected = (error) => {
        throw error;
      };
    }

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

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

    return promise;
  }
}

然后,我们就可以像之前一样使用这个Promise类了:

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() < 0.5) {
      resolve("成功!");
    } else {
      reject("失败!");
    }
  }, 1000);
});

promise.then((result) => {
  console.log(result);
}, (error) => {
  console.log(error);
});

总结

通过拆解需求,我们可以将手写Promise的过程分解为更小的步骤,从而使它变得更加容易理解和实现。希望本文能够帮助你掌握手写Promise的技巧,以便在面试中表现出色。