返回

揭开 Promise 之谜:从头开始亲手实现

前端

前言

在 JavaScript 的汪洋大海中,Promise 就像一艘航海利器,它帮助我们优雅地处理异步操作,避免回调地狱的困扰。今天,我们将抛开抽象,从头开始构建自己的 Promise 实现,深入探究其内部运作机制。

Promise 的前世今生

Promise,一个看似简单的概念,却有着不平凡的身世。它诞生于 ECMAScript 2015 规范中,旨在为异步操作提供一种更优雅、更可控的方式。在 Promise 出现之前,我们只能通过回调函数来处理异步操作,导致代码难以维护和理解。

动手实现 Promise

现在,让我们卷起袖子,开始我们自己的 Promise 实现之旅。

1. 状态管理

Promise 有三个状态:待定(pending)、已完成(fulfilled)和已拒绝(rejected)。我们需要创建三个常量来表示这些状态。

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

2. 执行函数

Promise 在创建时接受一个执行函数作为参数。此函数有两个形参:resolve 和 reject,它们用于改变 Promise 的状态。

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

3. 改变状态

resolve 和 reject 方法用于将 Promise 的状态从待定更改为已完成或已拒绝。它们接受一个值作为参数,该值将成为 Promise 的结果。

resolve(value) {
  if (this.state !== PENDING) return;
  this.state = FULFILLED;
  this.result = value;
  this.onFulfilled();
}

reject(error) {
  if (this.state !== PENDING) return;
  this.state = REJECTED;
  this.result = error;
  this.onRejected();
}

4. 回调队列

为了在 Promise 状态改变后执行回调函数,我们需要维护两个回调队列:onFulfilled 和 onRejected。

onFulfilled() {
  for (let callback of this.fulfillmentCallbacks) {
    callback(this.result);
  }
}

onRejected() {
  for (let callback of this.rejectionCallbacks) {
    callback(this.result);
  }
}

5. then() 方法

then() 方法是 Promise 的核心,它允许我们指定在 Promise 状态改变后要执行的回调函数。

then(onFulfilled, onRejected) {
  if (this.state === FULFILLED) {
    onFulfilled(this.result);
  } else if (this.state === REJECTED) {
    onRejected(this.result);
  } else {
    this.fulfillmentCallbacks.push(onFulfilled);
    this.rejectionCallbacks.push(onRejected);
  }

  return this;
}

6. catch() 方法

catch() 方法是 then() 方法的一个语法糖,它只处理 Promise 拒绝的情况。

catch(onRejected) {
  return this.then(null, onRejected);
}

应用实例

现在我们有了自己的 Promise 实现,让我们用一个例子来展示它的用法。

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功啦!');
  }, 2000);
});

promise
  .then((result) => {
    console.log(result); // 输出:成功啦!
  })
  .catch((error) => {
    console.error(error);
  });

结语

通过从头开始实现 Promise,我们不仅加深了对异步编程的理解,也领会了 Promise 的精妙之处。现在,我们可以在自己的代码中自信地使用 Promise,提升编程效率和代码可读性。欢迎留言分享你的见解和实践经验,让我们共同探索编程世界的无限可能!