请用js实现一个promise的方法

38 阅读2分钟

使用 JavaScript 实现 Promise

JavaScript 的 Promise 是一种用于处理异步操作的机制,它代表一个可能在未来完成或失败的操作及其结果值。下面我们将手动实现一个简单的 Promise 类,来深入理解其工作原理。

1. Promise 类的基本结构

首先,我们需要定义一个 Promise 类,并在构造函数中接受一个执行器函数(executor),该函数接收两个参数:resolvereject

class MyPromise {
  constructor(executor) {
    this.state = 'pending'; // 初始状态
    this.value = undefined;  // 成功时的值
    this.reason = undefined; // 失败时的原因
    this.onResolvedCallbacks = []; // 存储成功时的回调
    this.onRejectedCallbacks = []; // 存储失败时的回调

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled'; // 状态变为成功
        this.value = value;
        this.onResolvedCallbacks.forEach(callback => callback(value)); // 执行所有成功的回调
      }
    };

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected'; // 状态变为失败
        this.reason = reason;
        this.onRejectedCallbacks.forEach(callback => callback(reason)); // 执行所有失败的回调
      }
    };

    try {
      executor(resolve, reject); // 执行传入的函数
    } catch (err) {
      reject(err); // 捕获异常并拒绝
    }
  }

  // then 方法
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        // 如果已经成功,直接执行成功回调
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value);
            resolve(x);
          } catch (err) {
            reject(err);
          }
        });
      }

      if (this.state === 'rejected') {
        // 如果已经失败,直接执行失败回调
        setTimeout(() => {
          try {
            const x = onRejected(this.reason);
            resolve(x);
          } catch (err) {
            reject(err);
          }
        });
      }

      // 如果仍然是 pending,存储回调
      if (this.state === 'pending') {
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value);
              resolve(x);
            } catch (err) {
              reject(err);
            }
          });
        });

        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason);
              resolve(x);
            } catch (err) {
              reject(err);
            }
          });
        });
      }
    });
  }
}

2. Promise 的基本用法

现在我们已经实现了一个基本的 Promise 类,下面是如何使用它的示例。

const myPromise = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    const success = true; // 模拟成功或失败
    if (success) {
      resolve('操作成功');
    } else {
      reject('操作失败');
    }
  }, 1000);
});

myPromise
  .then(result => {
    console.log(result); // 输出: 操作成功
    return '继续处理';
  })
  .then(result => {
    console.log(result); // 输出: 继续处理
  })
  .catch(error => {
    console.error(error); // 如果失败,输出错误信息
  });

3. Promise.all 和 Promise.race

为了增强我们的 Promise 实现,我们可以添加 Promise.allPromise.race 方法。

MyPromise.all = function(promises) {
  return new MyPromise((resolve, reject) => {
    let resolvedCounter = 0;
    const results = [];
    
    promises.forEach((promise, index) => {
      promise.then(value => {
        resolvedCounter++;
        results[index] = value;

        if (resolvedCounter === promises.length) {
          resolve(results); // 所有 Promise 都成功时返回结果
        }
      }).catch(reject); // 任意一个 Promise 失败则直接 reject
    });
  });
};

MyPromise.race = function(promises) {
  return new MyPromise((resolve, reject) => {
    promises.forEach(promise => {
      promise.then(resolve).catch(reject);
    });
  });
};

结论

通过手动实现 Promise,我们可以更深入地理解其内部机制。Promise 提供了一种优雅的方式来处理异步操作,避免了回调地狱的问题。尽管 JavaScript 已经原生支持 Promise,但学习如何实现它有助于我们更好地掌握异步编程的理念。