当前位置: 首页 > news >正文

现代 JavaScript (ES6+) 入门到实战(五):告别回调地狱,Promise 完全入门

到目前为止,我们处理的都是同步代码——代码从上到下一行行执行,简单直接。但 JavaScript 的世界中,大量操作都是异步的,比如网络请求(AJAX)、文件读取、定时器等。它们不会阻塞主线程,而是在未来的某个时刻才返回结果。

在 ES6 之前,我们处理异步的唯一方式就是回调函数。当一个异步操作需要依赖另一个的结果时,灾难就降临了。

一、回忆杀:噩梦般的回调地狱 (Callback Hell)

假设我们需要依次请求三个接口:获取用户信息 -> 根据用户信息获取其帖子列表 -> 根据帖子 ID 获取评论。

【过去我们这么写 (ES5 - 以 jQuery Ajax 为例)】

$.ajax({url: 'api/user/1',success: function(user) {console.log('第一步:获取到用户', user.name);// 成功后,发起第二个请求$.ajax({url: 'api/posts/' + user.id,success: function(posts) {console.log('第二步:获取到帖子', posts.length, '篇');// 成功后,发起第三个请求$.ajax({url: 'api/comments/' + posts[0].id,success: function(comments) {console.log('第三步:获取到评论');// 如果还有第四步、第五步...},error: function(err) {console.error('获取评论失败', err);}});},error: function(err) {console.error('获取帖子失败', err);}});},error: function(err) {console.error('获取用户失败', err);}
});

这种向右无限延伸的“金字塔”结构,就是臭名昭著的“回调地狱”。它有三大罪状:

  1. 可读性极差:代码逻辑混乱,难以理解。
  2. 难以维护:修改其中一个环节,可能导致整个逻辑链的崩溃。
  3. 错误处理分散:每个异步操作都需要单独处理错误,代码冗余。

为了将开发者从地狱中解救出来,ES6 带来了官方的异步解决方案——Promise

二、进化时刻:Promise 登场

Promise 的中文意思是“承诺”。你可以把它想象成一张“承诺回执单”。

当你执行一个异步操作时,它不会立即给你结果,而是先给你一张“回执单”(即 Promise 对象)。这张单子向你承诺:“我将来一定会给你一个结果,要么是成功的结果,要么是失败的原因。”

一个 Promise 对象有三种状态:

  1. Pending (进行中):初始状态,承诺还在兑现中。
  2. Fulfilled (已成功):操作成功完成,承诺已兑现。
  3. Rejected (已失败):操作失败,承诺被拒绝。

这个状态是单向的,一旦从 pending 变为 fulfilledrejected,就再也不会改变。

三、如何使用 Promise?

现代的异步 API(如 fetch)天生就返回 Promise。我们先来学习如何“消费”一个 Promise。

1. .then() - 接收成功的结果
.then() 方法用于指定当 Promise 状态变为 fulfilled (成功) 时,应该执行什么操作。

2. .catch() - 捕获失败的原因
.catch() 方法用于指定当 Promise 状态变为 rejected (失败) 时,应该执行什么操作。

【现在我们这么写 (ES6+ - 以 fetch 为例)】
fetch 是浏览器内置的、基于 Promise 的网络请求 API。

fetch('api/user/1') // fetch 返回一个 Promise.then(response => {// 第一个 .then 处理 HTTP 响应if (!response.ok) {throw new Error('网络响应错误');}return response.json(); // .json() 也返回一个 Promise}).then(user => {// 第二个 .then 处理 JSON 数据console.log('成功获取到用户:', user);}).catch(error => {// 统一处理所有错误console.error('请求过程中发生错误:', error);});

四、Promise 的真正威力:链式调用

Promise 最强大的地方在于,它将“回调地狱”拉平成了一条直线,形成优雅的链式调用。

.then().catch() 方法执行后,它自身也会返回一个新的 Promise 对象,这使得我们可以像工厂流水线一样,将一系列异步操作串联起来。

现在,我们用 Promise 来重构开头的那个“地狱”:
(假设我们已经把 $.ajax 封装成返回 Promise 的函数 ajaxPromise)

【现在我们这么写 (ES6+)】

ajaxPromise('api/user/1').then(user => {console.log('第一步:获取到用户', user.name);// 返回一个新的 Promise,交给下一个 .then 处理return ajaxPromise('api/posts/' + user.id);}).then(posts => {console.log('第二步:获取到帖子', posts.length, '篇');return ajaxPromise('api/comments/'' + posts[0].id);}).then(comments => {console.log('第三步:获取到评论');}).catch(err => {// 统一的错误处理!// 链条中任何一个环节出错,都会被这个 catch 捕获console.error('链式调用中发生错误:', err);});

看到了吗?原本横向发展的“金字塔”,现在变成了纵向发展的“流水线”。代码结构清晰,逻辑一目了然,并且错误处理也变得非常简单、集中。

总结

  • Promise 是处理异步操作的对象,它代表一个未来的结果。
  • 它通过链式调用,完美地解决了回调地狱问题。
  • 使用 .then() 处理成功,使用 .catch() 统一处理失败。
  • .then() 中可以返回一个新的 Promise,从而将异步操作串联起来。

Promise 的出现,是 JavaScript 异步编程史上的一座里程碑。但进化并未停止。ES7 带来了 async/await,它能让异步代码看起来就像同步代码一样简洁。

在下一篇,我们将迎来异步编程的终极形态!敬请期待!

http://www.lqws.cn/news/574993.html

相关文章:

  • Origin绘制复合子母饼状图—复合柱饼图、复合环饼图及复合饼图
  • 爬虫实战之图片及人物信息爬取
  • 【IQA技术专题】大模型视觉强化学习IQA:Q-Insight
  • 数据同步工具对比:Canal、DataX与Flink CDC
  • 第二届 Parloo杯 应急响应学习——畸形的爱
  • Mybatis的修改(update)操作
  • 【Linux庖丁解牛】— 文件系统!
  • cJSON 使用方法详解
  • 浅谈AI大模型-MCP
  • 机器学习在智能电网中的应用:负荷预测与能源管理
  • Nginx漏洞处理指南
  • Leetcode 3598. Longest Common Prefix Between Adjacent Strings After Removals
  • 第8篇:Gin错误处理——让你的应用更健壮
  • 【Typst】自定义彩色盒子
  • 【NLP 实战】蒙古语情感分析:从 CNN 架构设计到模型训练的全流程解析(内附项目源码及模型成果)
  • BP-Tools21.02下载 加解密利器 金融安全交易算法工具 PCI认证工具 金融和智能卡的数据加解密和数据转换工具
  • 无人机用shell远程登录机载电脑,每次需要环境配置原因
  • 06_注意力机制
  • (七)集成学习
  • git lfs 提交、拉取大文件
  • 【Linux高级全栈开发】2.4 自研框架:基于 dpdk 的用户态协议栈的实现
  • 华为云Flexus+DeepSeek征文 | 华为云 ModelArts Studio 赋能 AI 法务:合同审查与法律文件生成系统
  • M|艺伎回忆录
  • 从理论到实战:解密大型语言模型的核心技术与应用指南
  • (LeetCode 面试经典 150 题 ) 134. 加油站 (贪心)
  • 日语学习-日语知识点小记-进阶-JLPT-真题训练-N2阶段(5):2022年12月2023年7月
  • 通过HTTPS访问Harbor2.13.1 的配置
  • 1.认识Docker
  • #华为鲲鹏#华为计算#鲲鹏开发者计划2025#
  • Prompt Depth Anything:以提示方式驱动的Depth Anything用于实现4K分辨率下的精确米制深度估计