返回

从零开始构建简易版Promise

前端

什么是 Promise?

在 JavaScript 的世界里,处理异步操作是一项至关重要的任务。Promise 应运而生,作为一种优雅的方式,让我们能够在代码中处理这些异步操作。本质上,它是一个对象,可以表示一个异步操作最终完成(或失败)及其结果。换句话说,它允许您将异步操作的结果传递给其他函数,从而使代码更加清晰和可读。

创建和使用 Promise

创建 Promise 非常简单。只需创建一个 new Promise 对象,其中包含一个 executor 函数。这个函数有两个参数:resolve 和 reject。当异步操作成功完成时,调用 resolve() 传递结果;当操作失败时,调用 reject() 传递错误信息。

const promise = new Promise((resolve, reject) => {
  // 异步操作在此处执行
  // resolve(result); // 成功时调用
  // reject(error); // 失败时调用
});

一旦 Promise 被创建,它可以有三种状态之一:

  • pending :初始状态,表示异步操作尚未完成。
  • resolved :异步操作已成功完成,并带有结果。
  • rejected :异步操作已失败,并带有错误信息。

要处理 Promise 的结果,可以使用 then() 方法。它接受两个参数:成功处理函数和失败处理函数。当 Promise 状态变为 resolved 时,成功处理函数会被调用,并传递结果作为参数。当 Promise 状态变为 rejected 时,失败处理函数会被调用,并传递错误信息作为参数。

promise.then((result) => {
  // 成功时执行
}, (error) => {
  // 失败时执行
});

此外,还可以使用 catch() 方法来处理 Promise 的错误。它只接受一个参数:失败处理函数。当 Promise 状态变为 rejected 时,失败处理函数会被调用,并传递错误信息作为参数。

promise.catch((error) => {
  // 失败时执行
});

Promise 的优点

使用 Promise 有几个好处:

  • 更清晰的代码结构 :Promise 可以大大简化异步代码的结构,让代码更加可读和可维护。
  • 简化错误处理 :Promise 可以让您更轻松地处理异步操作的错误,避免回调地狱的问题。
  • 更好的可读性 :Promise 使用 then() 和 catch() 方法来处理结果,这比使用回调函数更具可读性。

自定义一个 Promise

为了更深入地理解 Promise 的工作原理,您可以创建一个自己的 Promise 实现。以下是一个简单的 Promise 实现:

class SimplePromise {
  constructor(executor) {
    this.state = 'pending';
    this.result = undefined;
    this.error = undefined;
    this.onResolveCallbacks = [];
    this.onRejectCallbacks = [];

    const resolve = (result) => {
      if (this.state !== 'pending') return;
      this.state = 'resolved';
      this.result = result;
      this.onResolveCallbacks.forEach((callback) => callback(result));
    };

    const reject = (error) => {
      if (this.state !== 'pending') return;
      this.state = 'rejected';
      this.error = error;
      this.onRejectCallbacks.forEach((callback) => callback(error));
    };

    executor(resolve, reject);
  }

  then(onResolve, onReject) {
    return new SimplePromise((resolve, reject) => {
      if (this.state === 'resolved') {
        setTimeout(() => {
          try {
            const result = onResolve(this.result);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            const result = onReject(this.error);
            resolve(result);
          } catch (error) {
            reject(error);
          }
        }, 0);
      } else {
        this.onResolveCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onResolve(this.result);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
        this.onRejectCallbacks.push(() => {
          setTimeout(() => {
            try {
              const result = onReject(this.error);
              resolve(result);
            } catch (error) {
              reject(error);
            }
          }, 0);
        });
      }
    });
  }

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

结论

Promise 是处理 JavaScript 中异步操作的强大工具。它们可以帮助您简化代码结构,简化错误处理,并提高可读性。通过理解 Promise 的核心概念,您可以编写更健壮、更易于维护的异步代码。

常见问题解答

1. Promise 和回调函数有什么区别?

Promise 是一种对象,它可以表示异步操作的最终完成(或失败)及其结果。回调函数是一个在异步操作完成后调用的函数。Promise 的主要优点是它允许您以更结构化和可读的方式处理异步操作。

2. 如何处理 Promise 的错误?

可以使用 then() 方法的第二个参数或 catch() 方法来处理 Promise 的错误。这两个方法都接受一个失败处理函数作为参数,该函数在 Promise 状态变为 rejected 时被调用。

3. Promise 是否支持链式操作?

是的,Promise 支持链式操作。您可以将 then() 方法链接在一起,以创建一系列操作,每个操作都基于前一个操作的结果。

4. 如何在 Promise 中传递多个结果?

可以使用 Promise.all() 方法来传递多个结果。它接受一个 Promise 数组作为参数,并返回一个新的 Promise。当所有输入的 Promise 都已 resolved 时,此 Promise 将 resolved,并带有所有结果的数组。

5. 如何取消 Promise?

Promise 本身不支持取消。但是,您可以使用第三方库或手动实现来取消 Promise。