返回

从零打造一个精简的 Promise 实现

前端

引言

JavaScript 的异步编程模型是一把双刃剑。它提供了处理异步操作的灵活性,但同时也带来了难以管理的回调函数嵌套,也称为“回调地狱”。

为了解决这个问题,JavaScript 引入了 Promise,一种优雅而强大的机制,可以简化异步编程。它将异步操作封装在一种对象中,提供了一种统一的处理方式,并消除回调地狱的烦恼。

打造自己的 Promise 实现

本文将带你踏上一段旅程,一步步打造一个符合 Promises/A+ 规范的简易 Promise 实现。Promises/A+ 是一个规范,定义了 Promise 应该如何运作,以确保跨不同库的互操作性。

第一步:设置状态和结果

每个 Promise 都具有三种可能的状态:待定已解决已拒绝

const states = {
  PENDING: 'pending',
  FULFILLED: 'fulfilled',
  REJECTED: 'rejected'
};

结果是一个用于存储已解决或已拒绝 Promise 的值的变量。

let result;

第二步:创建 Promise 构造函数

构造函数用于创建一个新的 Promise 实例。它接受一个执行器函数作为参数,该函数将立即执行并传递两个函数:resolvereject

class Promise {
  constructor(executor) {
    this.state = states.PENDING;
    executor(this.resolve.bind(this), this.reject.bind(this));
  }
}

第三步:定义 resolve 和 reject

resolve 函数用于将 Promise 标记为已解决状态,并提供结果值。

resolve(value) {
  if (this.state === states.PENDING) {
    this.state = states.FULFILLED;
    result = value;
  }
}

reject 函数用于将 Promise 标记为已拒绝状态,并提供原因。

reject(error) {
  if (this.state === states.PENDING) {
    this.state = states.REJECTED;
    result = error;
  }
}

第四步:添加 then 方法

then 方法是 Promise 的核心。它用于在 Promise 已解决或已拒绝时执行回调函数。

then(onFulfilled, onRejected) {
  if (this.state === states.FULFILLED) {
    onFulfilled(result);
  } else if (this.state === states.REJECTED) {
    onRejected(result);
  } else {
    // 如果 Promise 仍处于待定状态,则将回调函数存储起来,以便在 Promise 解决或拒绝后执行
    this.onFulfilledCallbacks.push(onFulfilled);
    this.onRejectedCallbacks.push(onRejected);
  }
}

第五步:处理异步操作

最后一步是处理异步操作。为了简单起见,我们使用 setTimeout 函数模拟异步操作。

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('异步操作已完成!');
  }, 1000);
});

使用我们的 Promise 实现

现在,我们的 Promise 实现已经完成,我们可以使用它来处理异步操作。

myPromise
  .then(result => {
    console.log(result); // 输出:异步操作已完成!
  })
  .catch(error => {
    console.log(error);
  });

结论

通过构建自己的 Promise 实现,我们深入了解了 Promise 的工作原理以及它们如何简化异步编程。虽然我们创建的实现很简单,但它符合 Promises/A+ 规范,可以用于处理实际的异步操作。

我希望这篇文章能帮助你理解 Promise 的基本原理,并激发你进一步探索 JavaScript 的异步编程世界。