返回

通过函数调用反向实现 Promise A+ 规范

前端

函数调用与 Promise 的关联

在深入探讨 Promise 的实现之前,我们先来回顾一下函数调用的概念。函数调用是程序执行的基本单位,当我们调用一个函数时,函数内部的代码会被执行,并在执行完成后返回一个值。

Promise 与函数调用有着紧密的联系,它本质上是对回调函数的封装。在传统回调函数的模式中,当异步操作完成时,我们会通过回调函数来处理结果。然而,随着异步操作的增多,嵌套的回调函数会变得难以管理,这便是 Promise 诞生的动机。

Promise 通过将回调函数封装在一个对象中,提供了一种更加优雅和可控的方式来处理异步操作。Promise 对象的状态从 pending(等待)开始,当异步操作完成时,状态会转变为 fulfilled(已完成)或 rejected(已拒绝)。

反向实现 Promise A+ 规范

为了深入理解 Promise 的本质,我们从函数调用的角度反向实现 Promise A+ 规范。

  1. 定义 Promise 构造函数

Promise A+ 规范规定,Promise 构造函数接收一个执行器函数 executor,该函数有两个参数 resolve 和 reject,分别用于将 Promise 的状态转变为 fulfilled 和 rejected。

function Promise(executor) {
  this.state = 'pending'; // 状态
  this.value = undefined; // fulfilled 时存储值
  this.reason = undefined; // rejected 时存储原因
  this.onFulfilledCallbacks = []; // 存储 then 回调
  this.onRejectedCallbacks = []; // 存储 catch 回调

  executor(resolve.bind(this), reject.bind(this));
}
  1. 状态转换

Promise 的状态只能从 pending 转变为 fulfilled 或 rejected,并且一旦状态转变,将不可逆转。

function resolve(value) {
  if (this.state === 'pending') {
    this.state = 'fulfilled';
    this.value = value;
    this.onFulfilledCallbacks.forEach(cb => cb(value));
  }
}

function reject(reason) {
  if (this.state === 'pending') {
    this.state = 'rejected';
    this.reason = reason;
    this.onRejectedCallbacks.forEach(cb => cb(reason));
  }
}
  1. then 方法

then 方法用于在 Promise 异步操作完成后处理结果。它接收两个回调函数,onFulfilled 和 onRejected,分别处理 fulfilled 和 rejected 的情况。

Promise.prototype.then = function(onFulfilled, onRejected) {
  return new Promise((resolve, reject) => {
    this.onFulfilledCallbacks.push(value => {
      try {
        const result = onFulfilled(value);
        resolve(result);
      } catch (err) {
        reject(err);
      }
    });

    this.onRejectedCallbacks.push(reason => {
      try {
        const result = onRejected(reason);
        resolve(result);
      } catch (err) {
        reject(err);
      }
    });
  });
};
  1. catch 方法

catch 方法用于处理 rejected 的情况,它接收一个回调函数 onRejected,用于处理 rejected 的原因。

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

应用场景

理解 Promise A+ 规范并能够实现 Promise 后,我们可以将其应用于实际场景中。例如,我们可以在一个函数中使用 Promise 来处理异步操作,并通过 then 和 catch 方法来处理结果。

function fetchUserData() {
  return new Promise((resolve, reject) => {
    // 模拟异步操作
    setTimeout(() => {
      if (Math.random() > 0.5) {
        resolve({ name: 'John Doe', age: 30 });
      } else {
        reject('Failed to fetch user data');
      }
    }, 500);
  });
}

fetchUserData()
  .then(data => {
    // 处理已完成的情况
    console.log(`User name: ${data.name}`);
  })
  .catch(reason => {
    // 处理已拒绝的情况
    console.error('Failed to fetch user data:', reason);
  });

总结

通过从函数调用的角度反向实现 Promise A+ 规范,我们可以深入理解 Promise 的本质和机制。Promise 提供了一种优雅和可控的方式来处理异步操作,并广泛应用于各种 JavaScript 应用程序中。