红宝书第十七讲:通俗详解JavaScript的Promise与链式调用


红宝书第十七讲:通俗详解JavaScript的Promise与链式调用

资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲


一、Promise的作用:解决"回调地狱"的困境

Promise(承诺)是JavaScript管理异步操作 的工具,用于替代传统的嵌套回调链(回调地狱)。它能将异步代码线性化 ,让异步逻辑像步骤说明书一样清晰 ^1^[^4]。

传统回调地狱的代码(难以阅读和维护):

javascript 复制代码
// 示例:依次执行多个异步任务(层层嵌套的"金字塔")
delayedExecute('第一步', (result1) => {
  delayedExecute('第二步', (result2) => {
    delayedExecute('第三步', (result3) => { // 层层缩进 → 难以维护
      // ...
    });
  });
});

Promise链式调用的代码(清晰易读):

javascript 复制代码
fetchData()
  .then((result1) => process(result1))  // 步骤1
  .then((result2) => process(result2))  // 步骤2
  .then((result3) => process(result3))  // 步骤3
  .catch((error) => console.error(error)); // 统一错误处理

^[1](#1: 资料2提到Promise/A+规范用于统一异步编程模式 "#user-content-fn-2")^: 资料2提到Promise/A+规范用于统一异步编程模式
^[2](#2: 资料5对比回调地狱与Promise链式调用的代码结构优势 "#user-content-fn-5")^: 资料5对比回调地狱与Promise链式调用的代码结构优势


二、Promise的状态:3个阶段

每个Promise对象有3种状态 ^1^:

  1. Pending(等待中):初始状态,尚未完成
  2. Fulfilled(已成功):异步操作成功完成
  3. Rejected(已失败):异步操作失败或出现错误

三、链式调用:像流水线一样处理异步任务

链式调用的核心在于:每个then()/catch()/finally()都会返回一个新的Promise ,允许后续继续调用 ^3^^2^。

示例:分步骤模拟异步操作
javascript 复制代码
// 创建返回Promise的简单异步函数
function delay(ms, value) {
  return new Promise((resolve) => {
    setTimeout(() => resolve(value), ms);
  });
}

// 链式调用示例 → 每个then等待前一步完成
delay(1000, "第一步数据")
  .then((data) => {
    console.log(`收到:${data}`);
    return delay(1000, "第二步处理后的数据"); // 返回新Promise
  })
  .then((data) => {
    console.log(`收到:${data}`);
    return "直接返回的第三步结果(非Promise)";
  })
  .then(console.log); // 自动包装为已成功的Promise

// 输出:
// (1秒后)收到:第一步数据
// (2秒后)收到:第二步处理后的数据
// (2秒后)直接返回的第三步结果...

^[3](#3: 资料1说明then/catch的链式返回新Promise对象 "#user-content-fn-1")^: 资料1说明then/catch的链式返回新Promise对象
^[2](#2: 资料5展示通过then链式严格排序的异步执行 "#user-content-fn-5")^: 资料5展示通过then链式严格排序的异步执行

流程图解释链式调用:
flowchart LR start[启动Promise] --> F1[执行第一个then] F1 --> 成功?{是否成功} 成功? -- 是 --> F2[执行第二个then] 成功? -- 否 --> Catch[执行catch处理] F2 --> 成功2?{是否成功} 成功2? -- 是 --> F3[执行第三个then] 成功2? -- 否 --> Catch Catch --> Finally[执行finally清理]

四、错误处理:统一捕获异常

通过catch()集中处理链中的任何错误,不影响后续步骤 ^3^^4^。

示例:错误捕获后继续执行
javascript 复制代码
fetchData()
  .then(processStep1) 
  .then(() => { throw new Error("故意抛出错误"); }) // 中途出错
  .catch((error) => { 
    console.error(`捕获错误:${error}`);
    return "错误后的恢复数据"; 
  })
  .then((data) => console.log(`继续处理:${data}`)); // 继续链式

// 输出:
// 捕获错误:故意抛出错误
// 继续处理:错误后的恢复数据

^[4](#4: 资料6中通过catch处理多个请求的集合错误 "#user-content-fn-6")^: 资料6中通过catch处理多个请求的集合错误


五、应用场景与扩展知识

  1. 多个异步任务并行Promise.all([任务1, 任务2]))^4^
  2. 仅需第一个完成的任务 (如竞速请求:Promise.any([任务1, 任务2]))^4^
  3. 统一清理资源finally(() => { ... }),无论成功失败都会执行)

目录:总目录 上篇文章:红宝书第十六讲:通俗详解JavaScript回调函数与事件循环

脚注

Footnotes

  1. 《JavaScript高级程序设计(第5版)》提及Promise状态机与异步编程模式 2 3

  2. 《JavaScript高级程序设计(第5版)》对比传统回调与Promise链式代码结构 2 3

  3. 《JavaScript高级程序设计(第5版)》指出链式调用基于每个方法返回新Promise 2 3

  4. 《JavaScript高级程序设计(第5版)》说明使用Promise.any()处理最快响应结果 2 3 4

相关推荐
斯~内克3 分钟前
前端浏览器窗口交互完全指南:从基础操作到高级控制
前端
Mike_jia39 分钟前
Memos:知识工作者的理想开源笔记系统
前端
前端大白话40 分钟前
前端崩溃瞬间救星!10 个 JavaScript 实战技巧大揭秘
前端·javascript
loveoobaby41 分钟前
Shadertoy着色器移植到Three.js经验总结
前端
蓝易云44 分钟前
在Linux、CentOS7中设置shell脚本开机自启动服务
前端·后端·centos
浩龙不eMo44 分钟前
前端获取环境变量方式区分(Vite)
前端·vite
一千柯橘1 小时前
Nestjs 解决 request entity too large
javascript·后端
土豆骑士1 小时前
monorepo 实战练习
前端
土豆骑士1 小时前
monorepo最佳实践
前端
见青..1 小时前
【学习笔记】文件包含漏洞--本地远程包含、伪协议、加密编码
前端·笔记·学习·web安全·文件包含