手写 Promise 实现:从构造函数到测试代码

本文将带领你一步一步实现一个简单的 Promise 对象,帮助你深入理解 Promise 的工作原理。

1. 定义 Promise 构造函数

首先,我们定义一个名为 MyPromise 的构造函数,它接受一个参数 executor,这个参数是一个函数,我们通常称之为执行函数。执行函数会接受两个参数,resolvereject,它们都是函数,用来改变 Promise 的状态。

function MyPromise(executor) {
  let self = this;
  self.status = 'pending'; // 初始状态为 pending
  self.resolveValue = undefined; // 成功的返回值
  self.rejectReason = undefined; // 失败的原因
  self.resolveCallbacks = []; // 存储成功的回调函数
  self.rejectCallbacks = []; // 存储失败的回调函数

  function resolve(value) {
    if (self.status === 'pending') { // 只有在状态为 pending 时才能改变状态
      self.status = 'resolved'; // 改变状态为 resolved
      self.resolveValue = value; // 存储成功的返回值
      self.resolveCallbacks.forEach(cb => cb()); // 执行所有存储的成功回调函数
    }
  }

  function reject(reason) {
    if (self.status === 'pending') { // 只有在状态为 pending 时才能改变状态
      self.status = 'rejected'; // 改变状态为 rejected
      self.rejectReason = reason; // 存储失败的原因
      self.rejectCallbacks.forEach(cb => cb()); // 执行所有存储的失败回调函数
    }
  }

  try {
    executor(resolve, reject); // 执行传入的执行函数
  } catch (e) {
    reject(e); // 如果执行函数抛出异常,则认为是失败
  }
}

2. 设计 then 函数

then 函数是 Promise 最重要的组成部分之一,它接受两个参数,fullfail,分别表示当 Promise 成功或失败时要执行的回调函数。

MyPromise.prototype.then = function(full, fail) {
  let self = this;
  let promise2;

  full = typeof full === 'function' ? full : value => value; // 如果 full 不是函数,则默认返回成功的值
  fail = typeof fail === 'function' ? fail : reason => { throw reason }; // 如果 fail 不是函数,则默认抛出失败的原因

  if (self.status === 'resolved') { // 如果当前状态为 resolved,则直接执行成功回调函数
    promise2 = new MyPromise((resolve, reject) => {
      setTimeout(() => { // 异步执行,保证 promise2 的状态已经改变
        try {
          let x = full(self.resolveValue);
          resolvePromise(promise2, x, resolve, reject); // 处理成功回调函数的返回值,更新 promise2 的状态和返回值
        } catch (e) {
          reject(e); // 如果执行成功回调函数抛出异常,则认为是失败
        }
      }, 0);
    });
  } else if (self.status === 'rejected') { // 如果当前状态为 rejected,则直接执行失败回调函数
    promise2 = new MyPromise((resolve, reject) => {
      setTimeout(() => { // 异步执行,保证 promise2 的状态已经改变
        try {
          let x = fail(self.rejectReason);
          resolvePromise(promise2, x, resolve, reject); // 处理失败回调函数的返回值,更新 promise2 的状态和返回值
        } catch (e) {
          reject(e); // 如果执行失败回调函数抛出异常,则认为是失败
        }
      }, 0);
    });
  } else if (self.status === 'pending') { // 如果当前状态为 pending,则存储成功和失败回调函数
    promise2 = new MyPromise((resolve, reject) => {
      self.resolveCallbacks.push(() => {
        setTimeout(() => { // 异步执行,保证 promise2 的状态已经改变
          try {
            let x = full(self.resolveValue);
            resolvePromise(promise2, x, resolve, reject); // 处理成功回调函数的返回值,更新 promise2 的状态和返回值
          } catch (e) {
            reject(e); // 如果执行成功回调函数抛出异常,则认为是失败
          }
        }, 0);
      });
      self.rejectCallbacks.push(() => {
        setTimeout(() => { // 异步执行,保证 promise2 的状态已经改变
          try {
            let x = fail(self.rejectReason);
            resolvePromise(promise2, x, resolve, reject); // 处理失败回调函数的返回值,更新 promise2 的状态和返回值
          } catch (e) {
            reject(e); // 如果执行失败回调函数抛出异常,则认为是失败
          }
        }, 0);
      });
    });
  }

  return promise2; // 返回新的 promise 对象
}

3. 实现 resolvereject 函数

resolve 函数用于将 Promise 的状态变为成功,reject 函数用于将 Promise 的状态变为失败。

// 定义 resolve 函数
MyPromise.resolve = function(value) {
  if (value instanceof MyPromise) { // 如果传入的值本身就是 promise 对象,则直接返回
    return value;
  }
  return new MyPromise(resolve => resolve(value)); // 否则,封装成新的 promise 对象返回
}

// 定义 reject 函数
MyPromise.reject = function(reason) {
  return new MyPromise((resolve, reject) => reject(reason)); // 将失败的原因封装成新的 promise 对象返回
}

4. resolvePromise 函数

resolvePromise 函数用于处理 then 函数的返回值,它根据返回值的类型进行不同的处理,以更新下一个 Promise 的状态和返回值。

// 定义 resolvePromise 函数,用于处理 then 函数的返回值
function resolvePromise(promise2, x, resolve, reject) {
  let self = this;
  let called = false; // 防止多次调用

  if (promise2 === x) { // 如果 promise2 和返回值 x 是同一个对象,则抛出循环引用错误
    reject(new TypeError('Chaining cycle detected for promise'));
    return;
  }

  if (x instanceof MyPromise) { // 如果返回值 x 是 promise 对象,则等待其状态改变
    x.then(value => {
      resolvePromise(promise2, value, resolve, reject); // 处理 promise 对象的返回值
    }, reason => {
      reject(reason); // 如果 promise 对象失败,则直接将失败原因传递给 promise2
    });
  } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) { // 如果返回值 x 是对象或函数
    try {
      let then = x.then; // 尝试获取 x 的 then 方法
      if (typeof then === 'function') { // 如果 then 是函数,则认为 x 是 thenable 对象
        then.call(x, value => {
          if (called) return; // 如果已经调用过,则直接返回
          called = true;
          resolvePromise(promise2, value, resolve, reject); // 处理 thenable 对象的返回值
        }, reason => {
          if (called) return; // 如果已经调用过,则直接返回
          called = true;
          reject(reason); // 如果 thenable 对象失败,则直接将失败原因传递给 promise2
        });
      } else {
        resolve(x); // 如果 x 是普通对象或函数,则直接将其作为 promise2 的返回值
      }
    } catch (e) {
      if (called) return; // 如果已经调用过,则直接返回
      called = true;
      reject(e); // 如果获取 then 方法时抛出异常,则认为是失败
    }
  } else {
    resolve(x); // 如果返回值 x 是普通值,则直接将其作为 promise2 的返回值
  }
}

5. 测试代码

最后,我们编写一段测试代码来验证我们实现的 Promise 对象是否符合预期。

// 测试代码
let p = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('success');
    // reject('fail');
  }, 2000);
});

p.then(value => {
  console.log('resolve:', value);
  return 'new success';
}, reason => {
  console.log('reject:', reason);
}).then(value => {
  console.log('resolve:', value);
  throw new Error('new fail');
}, reason => {
  console.log('reject:', reason);
}).then(value => {
  console.log('resolve:', value);
}, reason => {
  console.log('reject:', reason);
});

console.log('end'); // 先输出 end,再输出 resolve 或 reject

总结

通过本文的讲解,你应该已经了解了如何从零开始手写实现 Promise 对象,并掌握了 Promise 的基本概念和工作原理。你可以根据实际需要对代码进行修改和完善,以满足不同的需求。


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

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