手写 Promise:从零开始实现 JavaScript Promise 对象

本文将带你一步步从零开始实现 JavaScript Promise 对象,深入理解 Promise 的运作机制。

1. Promise 的构造函数

首先,我们需要创建 Promise 的构造函数,它接收一个参数:执行函数 (executor function)。执行函数有两个参数,分别是 resolve 和 reject 函数,它们用于改变 Promise 的状态。

function MyPromise(executor) {
  this.status = 'pending';
  this.value = undefined;
  this.reason = undefined;
  this.onResolvedCallbacks = [];
  this.onRejectedCallbacks = [];

  const resolve = (value) => {
    if (this.status === 'pending') {
      this.status = 'resolved';
      this.value = value;
      this.onResolvedCallbacks.forEach((fn) => fn());
    }
  };

  const reject = (reason) => {
    if (this.status === 'pending') {
      this.status = 'rejected';
      this.reason = reason;
      this.onRejectedCallbacks.forEach((fn) => fn());
    }
  };

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

2. 实现 Promise 的核心功能

接下来,我们需要实现 Promise 的核心功能,包括:

  • 三种状态: pending (等待), resolved (成功), rejected (失败);初始状态为 pending,状态一旦改变便不可逆转。
  • then 函数: 接收两个参数:onResolved 和 onRejected,分别对应成功和失败时的回调函数。
  • resolve 和 reject 函数: 分别用于将 Promise 的状态更改为 resolved 和 rejected。
MyPromise.prototype.then = function (onResolved, onRejected) {
  onResolved = typeof onResolved === 'function' ? onResolved : (value) => value;
  onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason; };

  const promise2 = new MyPromise((resolve, reject) => {
    if (this.status === 'resolved') {
      setTimeout(() => {
        try {
          const x = onResolved(this.value);
          this.resolvePromise(promise2, x, resolve, reject);
        } catch (error) {
          reject(error);
        }
      }, 0);
    }

    if (this.status === 'rejected') {
      setTimeout(() => {
        try {
          const x = onRejected(this.reason);
          this.resolvePromise(promise2, x, resolve, reject);
        } catch (error) {
          reject(error);
        }
      }, 0);
    }

    if (this.status === 'pending') {
      this.onResolvedCallbacks.push(() => {
        setTimeout(() => {
          try {
            const x = onResolved(this.value);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (error) {
            reject(error);
          }
        }, 0);
      });

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

  return promise2;
};

MyPromise.prototype.resolvePromise = function (promise2, x, resolve, reject) {
  if (promise2 === x) {
    reject(new TypeError('Chaining cycle detected for promise'));
  }

  let called = false;

  if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      const then = x.then;

      if (typeof then === 'function') {
        then.call(
          x,
          (y) => {
            if (called) return;
            called = true;
            this.resolvePromise(promise2, y, resolve, reject);
          },
          (r) => {
            if (called) return;
            called = true;
            reject(r);
          }
        );
      } else {
        resolve(x);
      }
    } catch (error) {
      if (called) return;
      called = true;
      reject(error);
    }
  } else {
    resolve(x);
  }
};

MyPromise.prototype.catch = function (onRejected) {
  return this.then(undefined, onRejected);
};

MyPromise.resolve = function (value) {
  return new MyPromise((resolve) => {
    resolve(value);
  });
};

MyPromise.reject = function (reason) {
  return new MyPromise((resolve, reject) => {
    reject(reason);
  });
};

MyPromise.all = function (promises) {
  return new MyPromise((resolve, reject) => {
    const result = [];
    let count = 0;

    for (let i = 0; i < promises.length; i++) {
      promises[i].then(
        (value) => {
          result[i] = value;
          count++;

          if (count === promises.length) {
            resolve(result);
          }
        },
        (reason) => {
          reject(reason);
        }
      );
    }
  });
};

MyPromise.race = function (promises) {
  return new MyPromise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(
        (value) => {
          resolve(value);
        },
        (reason) => {
          reject(reason);
        }
      );
    }
  });
};

3. 测试代码

最后,我们编写一段测试代码来验证我们的自定义 Promise 对象。

const promise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('success');
  }, 1000);
});

promise
  .then(
    (value) => {
      console.log(value);
      return 'hello';
    },
    (reason) => {
      console.log(reason);
    }
  )
  .then(
    (value) => {
      console.log(value);
    },
    (reason) => {
      console.log(reason);
    }
  );

通过以上步骤,我们就成功地实现了自定义 Promise 对象,并且验证了它的功能。

注意: 为了简单起见,以上代码省略了一些 Promise 的特性,比如 Promise.allSettled、Promise.any 等。你可以在此基础上进一步扩展和完善你的 Promise 实现。

手写 Promise:从零开始实现 JavaScript Promise 对象

原文地址: https://www.cveoy.top/t/topic/nv9l 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录