javaScript 进阶之路 --- 《手写“回调地狱”》

news2024/10/5 17:26:57

前言: 可能初次看到这个标题,你会有些惊讶。我们不是要实现“手写 Promise ”吗?怎么变成了手写“回调地狱”了?“我老早看视频学习的时候就知道,我们要避免写成“回调地狱的格式,怎么到你这还要手写这玩意?博主你老标题党了...”

我相信有很多学习前端的小伙伴百分百遇到过这样的面试题: ---“为什么我们要用 Promise 去代替传统的回调函数?” 我相信有很多人都可以随口回答出:“为了避免回调地狱,因为回调地狱会带来xxx的后果....”

ok,那么现在我问你,假设现在面试官让你实现一个 “回调地狱”。你脑子里的代码会是怎样的呢?我建议你停下来思考三分钟🤔...

不要问为什么有这么令人无语的问题,因为这就是我实实在在的面试题之一。起初我觉得面试官在刁难我,然而当我真正理解了这个知识点以后,我非常感谢那位面试官,在去研究这个面试题答案的过程中,让我对 JS 有了更深层次的理解...所以在手写 Promise 之前,我希望你能先完成手写 回调地狱。

往下阅读之前,请自觉领取并完成阅读本文的前置任务(0/2)

  • JS 代码运行机制

  • 加深理解回调函数


一. 手写回调地狱

  1. 我们假设现在有这样的一个场景: 我们前端通过<input/>框,获取到了用户输入的年龄以后,前端需要把这个年龄数值传递给后端。然后后端拿到这个年龄数据经过处理计算,会在 1s 后返回一个年龄 +1 的结果给我们。

经过上篇的知识可得到,我们按上面的写法,result 将会是 undefined。我们如果想要拿到正确的数值,就需要给 addUserAge 传递一个回调函数。

2. 所以正确的写法应该是这样:

3. 好的,现在我们拿到了后端传递给我们的第一次数据。

4. 接下来,我们所有的逻辑代码都需要在这个回调函数内部去写。

什么意思呢?凡事需要用到 age+1 这个值的代码,都需要写进 addUserAge 函数的回调函数里。

5. 我们更具体的表现出上面这句话的含义。假设下面的某个页面场景,又需要向后端发起一次请求,让后端再把用户的年龄 +1,我们的页面才能呈现出正确的样式。这怎么办呢? ----注意: 这里为了方便区分,我们把第一次拿到的结果写为 result1 然后赋值给局部变量 age1,第二次的结果写为 result2,赋值给 age2,以此类推。

我们可以看到,第一秒返回了 数字2,再过一秒返回了 数字3

(tips:我这里再次提示,如果你这一步没看懂,我真心希望你们回过头先去看我另外两篇支线任务的内容再来往下继续看。因为这里是一个难点,确实不是第一次看就能直接明白什么意思的,有难度的知识往往都是基础知识堆积而成的,一定要脚踏实地慢慢来)

6. ok,我们两次的结果都正确拿到了。但是!我想你已经猜到了,我们在实际开发中,请求绝对不只两次。后面的页面,又又又需要我们再次将年龄 +1 然后才能正确展示,怎么办呢?注意!你后面的结果都是依赖上一步的结果进行的,所以我们又需要传递一个回调函数给 addUserAge 。可想而知,我们的后面的逻辑又只能在第三个 addUserAge 的回调函数内书写。

结果如下:

7. 聪明的你也可能猜到,同理,后面的某个页面需要拿到 age+6 的结果怎么办呢?也就是我需要调用 addAge 函数 6 次,我们的代码结构就会变成下面的这个样子

8. 上面的代码是我为了清晰的展示才调整的空行,假如我们现在没有空行。

看到黄色的金字塔了吗?这就是我们俗称的回调地狱(又称死亡金字塔)的由来。 你会发现这种代码读起来是真的又臭又长,可读性极差,可维护性极差。这还仅仅只是一个小的功能页面就已经堆叠成这样了,我们还没有做任何复杂的逻辑运算。

二. Promise 的出现

  1. 如你所见,用上面的“回调地狱”写法写出来的代码,毫不夸张的说就是屎山。你敢这样写,公司就不敢辞退你。因为这代码只有你能看懂!哈哈,开个笑话,接下来的日子里你看的懂还好,最糟糕的情况就是过了两天有可能连你自己都看不懂这坨代码了...🍦

  2. 这时候就迫切的需要一种解决方法来避免上面的书写方式。接下来有请我们的重量级嘉宾 Promise。👏我们先看这个单词的意思是什么。

​“承诺,保证”我们需要先理清设计者为什么要用 “承诺” 来表达这个构造函数。 ⚠️注意:

这里的“承诺”并不是指我保证给你一个“成功”的答复,而是指“不管成功还是失败”我都会通知你。更人性化的表达方式就是:我一定会给你一个答复,而不是我一定会给你一个“满意”的答复。

3. 如果你明白了上面的这句话。那么接下来让我们通过写代码加深一下理解。首先 Promise 是一个类,那么们就可以通过 new 去调用。

4. 看到报错了吗?我们先看一下错误信息。

它好像提示我们少了一个参数,参数的名字叫 executor。那这个executor 又是个什么呢?🤔

5. 真的不用太害怕,它就是一个普通的函数起了个洋气的名字而已。并且它是作为了参数传递给你 Promise 构造函数,那么它就是一个普通的回调函数而已。(真的,它就是一个普普通通的函数而已,不要把它想的太过神奇了。)

6. OK,你说我少给你一个函数作为参数,那我给你不就行了吗?

好像确实没报错了。但是你是不是忽略了什么事情?我们回过头看一下这个回调函数的介绍。

​英语不好的同学我强烈建议你去搜一下这段话的原意,我在这里简单的表达一下大概意思。

这个回调函数会用来初始化这个 promise 实例。这个回调函数会被传递两个参数,(is passed 注意这里需要理解是“被动语态”,这里是会“被传递”的意思。)一个叫 resolve的回调函数 一个叫 reject的回调函数。

7.可以得到下面的写法。

这里需要特别注意,在这里 resolve和 reject 是实参而不是形参。什么意思呢?意思就是它是可以直接被调用的。它是被 Promise 传递过来的,形参是在 Promise 类里定义的。这点我们会在后面的《手写 Promise》 里解释。

8. 好像还是有错,我们再看看。

这里它表达的意思不是特别好理解,我来简单解释一下。

resolve 函数的参数,就是我们之前去请求后端获得的那个返回值

9. 还记得我们之前的写法吗,我们是拿不到 result 的

接下来我们换一种写法,把它改造成 Promise 的写法。

注意:我们在这里为了模拟数据过了一会才能回来的场景,在实际项目中,setTimeout 那段函数其实就是我们向后端发请求的函数。

10. 现在我们知道,这个改造的 addUserAge1 函数会返回一个 Promise 实例。

我们先看一下这个实例身上到底是什么样子的。

我们这里我们关键先看这两个属性,我们的结果好像被保存到了一个叫 [[PromiseResult]] 的属性中。还有一个属性叫做 [[PromiseSate]]

三. Promise 的三个状态

1.这里我们先说明, [[PromiseSate]] 有三种状态 pendding,fulfilled 和 rejected。分别对应着数“据存放之前”,“数据存放成功”,“和数据存放失败”三种情况。

  1. “数据存放之前”是指你还没通过 resolve 或者 reject 去存放数据的时候。

2. “数据存放成功”就是上面我们刚刚调用 resolve 的结果,这里不再重复。

3. “和数据存放失败”就是我们调用 reject 函数保存的数据。

4. 那既然我已经看到了放在 [[PromiseResult]] 的结果,我该怎么去取呢?非常简单。

Promise 实例身上为我们提供了一个 then 方法。并且会把 [[PromiseResult]] 存放的值,传递给 then 方法的第一个回调函数的参数里。

我们看一下结果:

如果读过我之前文章的小伙伴,这种写法不知道你还熟悉吗?

如果这个能看懂,我相信你读懂后面的 《手写Promise》 一定没问题!!🎁

6. 如果是 reject 保存的数据,那么他会被传递给 then 方法的第二个回调函数的参数中。

ok,我们休息一下,不再讲 cath 等这些方法了,让我们慢慢消化一下。

四. 回到最初的问题

  1. 现在我们大致了解了 Promise 的基本原理。我们之前说过,“回调地狱” 的产生是因为我需要多次请求后端的数据,多次嵌套调用了回调函数,才产生了 金字塔 一样的代码结构。那我们的 Promise 是怎么就避免了这个呢?

  2. 下面的内容我们先忽略 reject ,我们只要搞懂 resolve,reject 我相信你会同样会马上理清楚。

3. 现在还是老问题,我下面的页面需要依靠 age1 继续 +1 才能得到正确的样式,我们先来看结论。

看一下结果:

4. 你发现了什么吗?

我在这里 return 了另一个 Promise 实例,然后我就可以接着 then 下去。

这里直接引出:then 方法的返回值会被当重新包装成 Promise 实例,完成“链式调用”

5. 聪明的你就可以猜到,我们接下来如果多次 age+1 的话。我就一直重复 then--> return --> then --> return 就行了。

6. 可以看出上面的代码写法,并没有出现一直向右倾斜的情况,要比之前代码的可读性强非常多的。这其实就是 Promise 帮我们完成的事情。

结语:

其实 Promise 相关还有非常多的知识,如 cath,finally等这些, 我单独一章讲完等话,害怕有的读者会消化不了。所以就把核心的概念先抛出来,如果你顺利的读懂里本文,那剩下没讲到的那些方法,我希望你可以自行去了解,我只能做一个引路人把核心概念给你捋清楚,打渔还需你自己。

如果有的小伙伴感觉没太读懂,我还是希望你能回过头把这两篇文章读熟,读透,再返过来读本篇文章。

  • JS 代码运行机制

  • 加深理解回调函数

如果你跟进了后续的《手写 Promise》,我相信你会看到一个不一样的 JS 世界。🎁~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/81247.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

论文投稿指南——中国(中文EI)期刊推荐(第5期)

&#x1f680; EI是国际知名三大检索系统之一&#xff0c;在学术界的知名度和认可度仅次于SCI&#xff01;&#x1f384;&#x1f388; 【前言】 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊。其中&#xf…

智能优化算法:蜣螂优化算法-附代码

智能优化算法&#xff1a;蜣螂优化算法 摘要&#xff1a;蜣螂优化算法( Dung beetle optimizer, DBO), 是由 Jiankai Xue 等于2022 年提出的一种群体智能优化算法。其灵感来源于蜣螂的生物行为过程&#xff0c;具有寻优能力强&#xff0c;收敛速度快的特点。 1.蜣螂优化算法 …

一款很火的智能化 Shell 工具多色彩优化命令显示结果可以替换系统默认的 Shell 工具,支持多平台免费开源使用

一款很火的智能化 Shell 工具多色彩优化命令显示结果可以替换系统默认的 Shell 工具&#xff0c;支持多平台免费开源使用。 Nushell&#xff0c;它是用Rust写的&#xff0c;安全性提高的同时&#xff0c;Bug率也降低了&#xff0c;NuShell 专注于实现以下目标&#xff1a; 1、…

【云原生】Prometheus AlertManager讲解与实战操作

文章目录一、概述二、AlertManager 架构三、AlertManager 部署1&#xff09;下载2&#xff09;配置3&#xff09;启动服务4&#xff09;与Prometheus集成四、在Prometheus中设置告警规则五、AlertManager 告警通道配置一、概述 Prometheus 包含一个报警模块&#xff0c;就是我们…

利用图文和代码深度解析操作系统OS的内存管理实现原理机制和算法

利用图文和代码深度解析操作系统OS的内存管理实现原理机制和算法。 内存作为计算机系统的组成部分,跟开发人员的日常开发活动有着密切的联系,我们平时遇到的Segment Fault、OutOfMemory、Memory Leak、GC等都与它有关。本文所说的内存,指的是计算机系统中的主存(Main Memo…

LIFT: Learned Invariant Feature Transform详细笔记

LIFT: Learned Invariant Feature Transform Paper: LIFT: Learned Invariant Feature Transform | SpringerLink Code: GitHub - cvlab-epfl/LIFT: Code release for the ECCV 2016 paper 文章目录Abstract思路来源LIFT文献来源方法&#xff1a;LIFTPipeline网络架构训练流程…

【网络】网络基础

文章目录依据覆盖范围的网络分类初识网络协议网络协议分层OSI分层模型TCP/IP分层模型网络协议栈中每一层的典型协议和典型设备应用层传输层网络层数据链路层物理层初识IP地址和MAC地址IP地址MAC地址网络是数据传输的解决方案。计算机数量由少变多&#xff0c;计算机由单台机器完…

火爆全球的网红OpenAI ChatGPT注册教程

地址&#xff1a;https://chat.openai.com/ 1. 登陆上去体验 写代码问题 Could you help me to write a C function to upload a file to ASW S3?回复 带代码和注释 Sure, here is an example of how you might write a C function to upload a file to Amazon S3: #incl…

Redis Cluster高可用集群部署

​欢迎光临我的博客查看最新文章: https://river106.cn Redis从3.0开始支持Redis Cluster集群部署&#xff0c;在3.0之前使用哨兵模式来实现Redis集群&#xff08;利用Sentinel来监控master节点的状态&#xff0c;如果master节点异常&#xff0c;则将其中一台slave切换为master…

C语言中的void

文章目录一.void概要二.void应用场景2.1void能定义变量吗&#xff1f;2.2void这个类型有大小吗&#xff1f;2.3void*能定义变量吗&#xff1f;2.4void*使用2.5void*能不能进行对应的指针运算&#xff1f;2.6void和函数返回值2.7函数void类型的参数一.void概要 void就是空的意思…

多种方法帮你解决tomcat项目部署,idea控制台乱码问题

解决在使用Tomcat过程中idea控制台出现的乱码问题 以下将介绍几种方法&#xff08;都是小编亲测实用的方法&#xff09;&#xff0c;尝试并寻找适合自己的方法即可 由于我已经处理过了乱码问题&#xff0c;我就重新配置一下 &#xff08;我有效解决的方案是把-Dfile.encoding…

SQL开窗函数之前后函数(LEAD、LAG)

开窗函数 当我们需要进行一些比较复杂的子查询时&#xff0c;聚合函数就会非常的麻烦&#xff0c;因此可以使用开窗函数进行分组再运用函数查询。窗口函数既可以显示聚集前的数据&#xff0c;也可以显示聚集后的数据&#xff0c;可以在同一行中返回基础行的列值和聚合后的结果…

cubeIDE开发, 全面解析cubeMX图形配置工具

一、cubeIDE 集成cubeMX STM32CubeMX是st公司早期产品&#xff0c;现已经成为STM32Cube开发套件的一部分&#xff0c;直接集成到cubeIDE 开发平台省&#xff0c;是一种芯片引脚图形配置工具&#xff0c;可以非常轻松地配置STM32微控制器和微处理器&#xff0c;以及为Arm Cortex…

java+MySQL基于ssm的公文流转关管理系统

在企业的日常管理过程中,公文管理是日常管理中必不可少的组成部分,其管理水平的高低体现了一个企业管理水平的整体状况。一直以来企业使用传统人工的方式管理公文数据,这种管理方式存在着许多缺点,如:效率低、保密性差,另外时间一长,将产生大量的文件和数据,为操作人员带来不少…

python_selenium自动化测试框架

设计思路 本文整理归纳以往的工作中用到的东西&#xff0c;现汇总成基础测试框架提供分享。 框架采用python3 selenium3 PO yaml ddt unittest等技术编写成基础测试框架&#xff0c;能适应日常测试工作需要。 1、使用Page Object模式将页面定位和业务操作分开&#xff0…

cdp4j爬虫自动化学习

cdp4j爬虫自动化学习cdp4j介绍依赖通过识别本地文件进行调试cdp4j介绍 cdp4j是一个Java库&#xff0c;它提供了高级API来通过DevTools协议控制Chrome或Chromium。它可以用于自动使用网页和测试网页。cdp4j默认情况下可以完全运行&#xff0c;但可以配置为运行无头Chrome或Chro…

Spring Cloud Eureka 服务注册中心怎么配置

Eureka&#xff0c;这里是 Spring Cloud Eureka 的简称&#xff0c;是 Spring Cloud Netflix 组件之一。Spring Cloud Netflix 中核心的组件包括了服务治理&#xff08;Eureka&#xff09;&#xff0c;服务容断&#xff08;Hystrix&#xff09;&#xff0c;路由&#xff08;Zuu…

hypermesh和lsdyna联合仿真计算某汽车座椅进行的头冲吸能实验

导读&#xff1a;本案例运用hypermesh和lsdyna联合仿真&#xff0c;主要是针对某座椅进行的头冲吸能实验的仿真计算。这个工况考察座椅背部的塑料件的破坏情况&#xff0c;以及头部模块的加速度情况&#xff0c;达到保护人头部的效果。 本案例用户可以学习到&#xff1a; 1…

大学生程序设计创新实践基地2022年冬季校赛(NPU ACM Winter Contest)

大学生程序设计创新实践基地2022年冬季校赛&#xff08;NPU ACM Winter Contest&#xff09; 总述 总体考察对于板子的熟练变换&#xff0c;以及考察离谱地使用python和对getchar()以及EOF的基础掌握程度。 B&#xff0c;D&#xff0c;E是防AK题目。 题解 A死锁 ​ input…

【第九章 SQL优化_插入数据,主键优化,order by优化】

第九章 SQL优化_插入数据&#xff0c;主键优化&#xff0c;order by优化 1.插入数据&#xff1a; &#xff08;1&#xff09;insert&#xff1a; &#xff08;1&#xff09;批量插入数据&#xff1a; Insert into tb_test values(1,Tom),(2,Cat),(3,Jerry); &#xff08;2&am…