返回

从零实现一个 Promise 的内在逻辑和实战应用

前端

从头开始实现 Promise

为了更深入地理解 Promise 的运行机制,让我们从零开始实现一个简易版的 Promise。首先,我们先来定义一个 Promise 类:

class Promise {
  constructor(executor) {
    this.status = "pending"; // Promise 的初始状态是 pending
    this.value = undefined; // Promise 的值,在 resolve 时确定
    this.reason = undefined; // Promise 的原因,在 reject 时确定
    this.onResolveCallbacks = []; // 保存 then 回调函数,在 resolve 时执行
    this.onRejectCallbacks = []; // 保存 then 回调函数,在 reject 时执行

    // 立即执行 executor 函数
    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      // 如果 executor 函数抛出错误,则以 reject 状态扭转 Promise
      this.reject(error);
    }
  }

  resolve(value) {
    if (this.status === "pending") {
      this.status = "fulfilled"; // 将 Promise 状态变更为 fulfilled
      this.value = value; // 将 Promise 的值设置为给定值
      this.onResolveCallbacks.forEach(callback => callback(value)); // 执行所有 then 回调函数
    }
  }

  reject(reason) {
    if (this.status === "pending") {
      this.status = "rejected"; // 将 Promise 状态变更为 rejected
      this.reason = reason; // 将 Promise 的原因设置为给定原因
      this.onRejectCallbacks.forEach(callback => callback(reason)); // 执行所有 then 回调函数
    }
  }

  then(onResolve, onReject) {
    // 如果 onResolve 或 onReject 为空,则直接返回一个新的 Promise
    if (typeof onResolve !== "function") {
      onResolve = value => value;
    }
    if (typeof onReject !== "function") {
      onReject = reason => { throw reason; };
    }

    // 返回一个新的 Promise 对象
    return new Promise((resolve, reject) => {
      // 将 then 回调函数添加到回调数组中
      this.onResolveCallbacks.push(value => {
        try {
          // 执行 then 回调函数,并把结果作为新的 Promise 的值
          const result = onResolve(value);
          resolve(result); // 以 resolve 状态扭转新的 Promise
        } catch (error) {
          // 如果 then 回调函数抛出错误,则以 reject 状态扭转新的 Promise
          reject(error);
        }
      });

      this.onRejectCallbacks.push(reason => {
        try {
          // 执行 then 回调函数,并把结果作为新的 Promise 的值
          const result = onReject(reason);
          resolve(result); // 以 resolve 状态扭转新的 Promise
        } catch (error) {
          // 如果 then 回调函数抛出错误,则以 reject 状态扭转新的 Promise
          reject(error);
        }
      });
    });
  }
}

实战应用:Promise 的妙用

为了更好地理解 Promise 的实际应用,让我们来看一个简单的示例。假设我们有一个异步函数 fetchUser,它从服务器获取用户信息。我们希望在获取用户信息后,再执行一些操作,例如更新 UI。

// 获取用户信息的异步函数
const fetchUser = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // 模拟从服务器获取用户信息
      const user = { name: "John Doe", age: 30 };
      resolve(user); // 以 resolve 状态扭转 Promise,并传入用户信息
    }, 1000);
  });
};

// 使用 Promise 链式调用来更新 UI
fetchUser()
  .then(user => {
    // 更新 UI,显示用户信息
    document.getElementById("user-name").innerHTML = user.name;
    document.getElementById("user-age").innerHTML = user.age;
  })
  .catch(error => {
    // 处理错误情况
    console.error(error);
  });

在这个示例中,我们首先调用 fetchUser 函数获取用户信息,并返回一个 Promise。然后,我们使用 then 方法来注册一个回调函数,当 Promise 状态变更为 resolved 时,该回调函数将被执行,并在回调函数中更新 UI。如果 Promise 状态变更为 rejected,则会执行 catch 方法中的回调函数,并在该回调函数中处理错误情况。

结语

Promise 作为 JavaScript 中一项强大的异步编程工具,它可以帮助我们更优雅地处理异步任务,并编写出更易读、更易维护的代码。通过本文的深入剖析,您应该已经对 Promise 的工作原理有了更清晰的认识。