返回

亲手打造Promise:征服异步编程世界

前端

从零实现Promise:揭秘异步编程的神秘面纱

在纷繁多变的编程世界里,异步编程就好比是舞动的数据精灵,在时间与空间的交错中,翩翩起舞。而Promise,则是驾驭这些精灵的魔术棒,让我们能够优雅地处理异步操作,让代码井然有序。今天,我们就来亲手打造一个Promise,揭开它的神秘面纱,踏上异步编程的征途。

序幕:异步编程的舞台

在计算机的世界里,同步和异步就如同硬币的两面,相辅相成。同步编程就像是在排队等候,你需要一步步地完成每一项任务,才能继续前进。而异步编程则像是同时处理多项任务,你可以先把任务交给计算机去执行,然后继续做其他事情,等任务完成后再回来处理。

异步编程在现代开发中扮演着至关重要的角色。它能够提升程序的响应速度,提高资源利用率,让我们的代码更加灵活高效。然而,异步编程也带来了一些挑战,比如难以控制任务的执行顺序、处理错误和协调数据流等。

登场:Promise的闪耀时刻

为了应对异步编程的挑战,JavaScript社区创造了Promise。Promise是一个对象,它代表着某个异步操作的最终完成或失败。当异步操作完成后,Promise的状态会发生改变,并通知等待它的代码。

Promise的出现,极大地简化了异步编程。我们可以通过链式调用Promise,轻松地处理多个异步操作,让代码更加清晰易读。同时,Promise还提供了丰富的错误处理机制,让我们能够优雅地处理异步操作中的异常情况。

一、Promise的结构与生命周期

Promise拥有三个状态:pending(等待)、fulfilled(完成)和rejected(拒绝)。当Promise被创建时,它的状态为pending。当异步操作成功完成后,Promise的状态变为fulfilled,并携带一个结果值。如果异步操作失败,则Promise的状态变为rejected,并携带一个错误值。

二、Promise的链式调用

Promise的链式调用是其最强大的特性之一。我们可以通过链式调用,将多个异步操作串联起来,形成一个异步任务队列。当一个异步操作完成后,它的结果会自动传递给下一个异步操作,如此往复,直到整个队列中的所有异步操作都完成。

三、Promise的错误处理

Promise提供了两种错误处理机制:catch()方法和finally()方法。catch()方法用于捕获Promise中发生的错误,而finally()方法无论Promise是成功还是失败都会执行。

亲手实现Promise:揭开神秘代码的面纱

现在,让我们亲自动手实现一个Promise,一睹它的代码风采。

class Promise {
  constructor(executor) {
    this.state = 'pending'; // 初始状态为等待
    this.result = undefined; // 结果值
    this.error = undefined; // 错误值
    this.onFulfilledCallbacks = []; // 存储成功回调函数
    this.onRejectedCallbacks = []; // 存储失败回调函数

    const resolve = (value) => {
      if (this.state !== 'pending') return; // 状态不是等待则忽略

      this.state = 'fulfilled'; // 状态改为成功
      this.result = value; // 保存结果值

      // 依次调用所有成功回调函数
      this.onFulfilledCallbacks.forEach((callback) => {
        callback(value);
      });
    };

    const reject = (error) => {
      if (this.state !== 'pending') return; // 状态不是等待则忽略

      this.state = 'rejected'; // 状态改为失败
      this.error = error; // 保存错误值

      // 依次调用所有失败回调函数
      this.onRejectedCallbacks.forEach((callback) => {
        callback(error);
      });
    };

    // 立即执行executor,executor负责调用resolve或reject
    try {
      executor(resolve, reject);
    } catch (error) {
      reject(error); // 如果executor抛出错误,则直接调用reject
    }
  }

  then(onFulfilled, onRejected) {
    // 参数可选,如果为null或undefined则忽略
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
    onRejected = typeof onRejected === 'function' ? onRejected : (error) => { throw error; };

    // 返回一个新的Promise对象
    return new Promise((resolve, reject) => {
      // 根据当前Promise的状态,决定如何处理回调函数
      if (this.state === 'fulfilled') {
        // 如果当前Promise已成功,则立即执行成功回调函数
        setTimeout(() => {
          try {
            const result = onFulfilled(this.result); // 调用成功回调函数
            resolve(result); // 将结果传递给新的Promise
          } catch (error) {
            reject(error); // 如果回调函数抛出错误,则调用reject
          }
        }, 0);
      } else if (this.state === 'rejected') {
        // 如果当前Promise已失败,则立即执行失败回调函数
        setTimeout(() => {
          try {
            const result = onRejected(this.error); // 调用失败回调函数
            resolve(result); // 将结果传递给新的Promise
          } catch (error) {
            reject(error); // 如果回调函数抛出错误,则调用reject
          }
        }, 0);
      } else {
        // 如果当前Promise仍在等待,则将回调函数存储起来,等待状态改变后执行
        this.onFulfilledCallbacks.push(() => {
          // 状态改为成功后,执行成功回调函数
          setTimeout(() => {
            try {
              const result = onFulfilled(this.result); // 调用成功回调函数
              resolve(result); // 将结果传递给新的Promise
            } catch (error) {
              reject(error); // 如果回调函数抛出错误,则调用reject
            }
          }, 0);
        });

        this.onRejectedCallbacks.push(() => {
          // 状态改为失败后,执行失败回调函数
          setTimeout(() => {
            try {
              const result = onRejected(this.error); // 调用失败回调函数
              resolve(result); // 将结果传递给新的Promise
            } catch (error) {
              reject(error); // 如果回调函数抛出错误,则调用reject
            }
          }, 0);
        });
      }
    });
  }

  catch(onRejected) {
    // 返回一个新的Promise对象,用于处理错误
    return this.then(null, onRejected);
  }

  finally(onFinally) {
    // 返回一个新的Promise对象,用于处理最终操作
    return this.then(
      (result) => {
        // 成功回调函数中执行最终操作
        onFinally();
        return result;
      },
      (error) => {
        // 失败回调函数中执行最终操作
        onFinally();
        throw error;
      }
    );
  }
}

结语:站在巨人的肩膀上

Promise的出现,标志着JavaScript异步编程迈出了里程碑式的一步。它让异步编程变得更加简单、优雅和可靠。然而,Promise也并非完美无缺。它有一些局限性,比如不支持取消异步操作、不支持并发控制等。

为了弥补Promise的不足,人们创造了更多的异步编程解决方案,比如async/await、Observable等。这些解决方案各有千秋,开发者可以根据自己的需求选择合适的方案。

异步编程是一门深奥的学问,需要不断学习和实践才能掌握其精髓。希望今天的分享能够对你有所启发,让你在异步编程的道路上越走越远。