JavaScript 中的 Promise API 全面解析

在现代 JavaScript 开发中,异步编程是不可避免的重要部分。无论是处理网络请求、读取文件,还是与数据库交互,我们都离不开异步操作。而 Promise,作为 ES6 引入的异步解决方案之一,在实际开发中发挥着核心作用。本文将深入探讨 JavaScript 中的 Promise API,帮助读者全面理解其工作原理、常用方法及应用场景。

一、Promise 是什么?

Promise 是 JavaScript 中用于处理异步操作的一种对象。它代表了某个异步操作最终可能完成(fulfilled)或失败(rejected)的一种值。

1.1 Promise 的定义

js 复制代码
const promise = new Promise((resolve, reject) => {
  // 异步操作
  if (/* 成功 */) {
    resolve(value); // 成功时调用
  } else {
    reject(error);  // 失败时调用
  }
});

1.2 Promise 的三种状态

Promise 有三种状态:

  • pending(进行中):初始状态,既没有被 fulfilled,也没有被 rejected。

  • fulfilled(已成功):操作成功完成。

  • rejected(已失败):操作失败。

一旦状态改变,就不可再更改,即 Promise 是不可逆的。

二、Promise 的基本用法

2.1 then() 方法

用于注册成功和失败的回调函数。

js 复制代码
promise
  .then((value) => {
    console.log("成功:", value);
  })
  .catch((error) => {
    console.error("失败:", error);
  });

2.2 catch() 方法

是 then(null, rejection) 的语法糖,用于捕获异常。

js 复制代码
promise.catch((error) => {
  console.error("发生错误:", error);
});

2.3 finally() 方法

不论 Promise 最终是成功还是失败,finally() 中的回调都会执行。

js 复制代码
promise
  .then((value) => {
    console.log("成功", value);
  })
  .catch((error) => {
    console.error("失败", error);
  })
  .finally(() => {
    console.log("无论成功或失败都执行");
  });

三、Promise 链式调用

Promise 最大的优点之一就是链式调用。你可以通过连续的 then() 方法来处理多个异步操作。

js 复制代码
fetchData()
  .then((data) => processData(data))
  .then((result) => renderData(result))
  .catch((error) => console.error(error));

这样写的好处是避免了"回调地狱"(callback hell),代码结构更清晰。

四、Promise 的静态方法

4.1 Promise.resolve()

返回一个状态为 fulfilled 的 Promise 对象。

js 复制代码
Promise.resolve("ok").then((res) => console.log(res)); // 输出 "ok"

4.2 Promise.reject()

返回一个状态为 rejected 的 Promise 对象。

js 复制代码
Promise.reject("error").catch((err) => console.error(err)); // 输出 "error"

4.3 Promise.all()

并发执行多个 Promise,并在全部成功后返回结果数组。

js 复制代码
const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = Promise.resolve(3);

Promise.all([p1, p2, p3]).then((values) => {
  console.log(values); // [1, 2, 3]
});

⚠️ 注意:只要有一个 Promise 失败,整个 Promise.all 就会失败。

4.4 Promise.race()

多个 Promise 中只要有一个改变状态(无论成功或失败),就立即返回该结果。

js 复制代码
Promise.race([
  new Promise((res) => setTimeout(() => res("快的"), 100)),
  new Promise((res) => setTimeout(() => res("慢的"), 200)),
]).then((res) => {
  console.log(res); // 输出 "快的"
});

4.5 Promise.allSettled()

与 Promise.all() 类似,但无论失败与否,都能返回每个 Promise 的最终状态。

js 复制代码
Promise.allSettled([
  Promise.resolve(1),
  Promise.reject("失败"),
]).then((results) => {
  console.log(results);
  // [
  //   { status: 'fulfilled', value: 1 },
  //   { status: 'rejected', reason: '失败' }
  // ]
});

4.6 Promise.any()

只要其中一个 Promise 成功,就返回成功的结果。若全部失败,则返回 AggregateError。

js 复制代码
Promise.any([
  Promise.reject("错误1"),
  Promise.resolve("成功的"),
  Promise.reject("错误2"),
]).then((value) => {
  console.log(value); // 成功的
});

五、实现一个简单的 Promise

为了深入理解 Promise 的原理,我们来模拟一个简单的 Promise 实现:

js 复制代码
class MyPromise {
  constructor(executor) {
    this.status = "pending";
    this.value = undefined;
    this.reason = undefined;

    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.status === "pending") {
        this.status = "fulfilled";
        this.value = value;
        this.onResolvedCallbacks.forEach((fn) => fn());
      }
    };

    const reject = (reason) => {
      if (this.status === "pending") {
        this.status = "rejected";
        this.reason = reason;
        this.onRejectedCallbacks.forEach((fn) => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  then(onFulfilled, onRejected) {
    if (this.status === "fulfilled") {
      onFulfilled(this.value);
    }

    if (this.status === "rejected") {
      onRejected(this.reason);
    }

    if (this.status === "pending") {
      this.onResolvedCallbacks.push(() => onFulfilled(this.value));
      this.onRejectedCallbacks.push(() => onRejected(this.reason));
    }
  }
}


六、Promise 与 async/await
ES2017 引入了 async/await,它是基于 Promise 的语法糖,使异步代码更像同步代码,易于编写和维护。
async function fetchData() {
  try {
    const res = await fetch("https://api.example.com");
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

await 后面的表达式必须是一个 Promise。async 函数会自动返回一个 Promise。

七、Promise 的异常处理机制

Promise 具有链式的异常传递机制。如果 then 中抛出了错误,后续的 catch 会捕获它。

js 复制代码
Promise.resolve()
  .then(() => {
    throw new Error("出错了");
  })
  .catch((err) => {
    console.error("捕获异常:", err.message); // 捕获异常:出错了
  });

此外,如果在 catch 之后继续写 then,Promise 会恢复为成功状态。

js 复制代码
Promise.reject("失败")
  .catch((err) => {
    console.log("处理失败:", err);
    return "默认值";
  })
  .then((res) => {
    console.log("恢复执行:", res); // 恢复执行:默认值
  });

八、实际开发中的 Promise 应用

8.1 接口请求并发处理

js 复制代码
async function loadAllData() {
  const [userInfo, articles, comments] = await Promise.all([
    fetchUserInfo(),
    fetchArticles(),
    fetchComments(),
  ]);

  console.log(userInfo, articles, comments);
}

8.2 防抖节流后的 Promise 延时

js 复制代码
function delay(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function run() {
  console.log("开始");
  await delay(1000);
  console.log("1 秒后执行");
}

九、常见错误与注意事项

  • then 中不返回新的 Promise:容易造成逻辑中断。

  • 未处理 catch 异常:会导致 Promise "吞掉"异常。

  • 在循环中使用 Promise:要注意执行顺序和并发控制。

  • Promise 状态不可逆:resolve/reject 只能调用一次。

十、总结

  • Promise 是处理异步操作的强大工具,具有链式调用、错误捕获、并发处理等优势。

  • 它有三种状态:pending、fulfilled 和 rejected,一旦状态确定,就不可再更改。

  • 提供多个静态方法如 Promise.all, Promise.race, Promise.allSettled 等,满足不同需求。

  • async/await 是基于 Promise 的语法糖,更加简洁优雅。

  • 理解 Promise 的机制和链式调用,有助于编写更健壮、更清晰的异步代码。

如果你在实际项目中深入使用 Promise,一定会体会到它为异步编程带来的清晰结构与可维护性。在未来的开发中,配合 async/await,将进一步提升你的开发效率和代码质量。

欢迎关注我的公众号获取更多技术干货!

相关推荐
@Dream_Chaser5 分钟前
uniapp ruoyi-app 中使用checkbox 无法选中问题
前端·javascript·uni-app
深耕AI7 分钟前
【教程】在ubuntu安装Edge浏览器
前端·edge
倔强青铜三11 分钟前
苦练Python第4天:Python变量与数据类型入门
前端·后端·python
倔强青铜三20 分钟前
苦练Python第3天:Hello, World! + input()
前端·后端·python
上单带刀不带妹21 分钟前
JavaScript中的Request详解:掌握Fetch API与XMLHttpRequest
开发语言·前端·javascript·ecmascript
倔强青铜三38 分钟前
苦练Python第2天:安装 Python 与设置环境
前端·后端·python
ningmengjing_40 分钟前
在 PyCharm 中安装并配置 Node.js 的指南
开发语言·javascript·ecmascript
我是若尘1 小时前
Webpack 入门到实战 - 复习强化版
前端
晓13131 小时前
JavaScript基础篇——第五章 对象(最终篇)
开发语言·前端·javascript
倔强青铜三1 小时前
苦练Python第1天:为何要在2025年学习Python
前端·后端·python