javaScript 进阶之路 --- 《加深理解回调函数》

news2024/9/20 16:50:21

前言: 回想当初第一次看到“回调函数”这个名词的时候,真的快把我难哭了。所有视频教程在讲到某个知识点的时候,大概都会说一句:“啊,这里怎么办呢?这里我们就需要用到一个回调函数...”。

等等,喂,关键是你还没讲什么是回调函数啊!,你让我怎么往下继续听啊...于是留下我一个人看着后面几十分钟的视频,但是脑子里还在纠结这个“回调函数”到底是什么玩意。

注意: 本文的前提知识是你需要了解 href="https://juejin.cn/post/7172948984145641479">JS 的执行机制。我强烈建议你先熟悉前提知识点再往下看,因为我们最终的目的是手写 Promise ,但是之前讲解的这些知识点是需要你必须掌握的。


一. 函数

  1. 回调函数的基本概念我之前的文章虽然有些过,但是为了引入下文,在这里还是简单再提一嘴。我们先看一下 MDN 的解释。

2.什么意思呢?还拿我们上一章节的例子。一个 setTimeout 里,隔了1秒去控制台打印一个 conole.log() 。

3.让我们拆解一下。我们仔细看下面的一行代码,你发现了吗?我只不过是把声明一个箭头函数,变为了定义一个匿名函数。其实这两种写法的所产生的效果是一模一样的。(请暂时不要考虑箭头函数和普通函数的区别)


在这种情况下,上面的匿名函数箭头函数统称为函数 setTimeout 的回调函数。你一定需要明白的事情就是 setTimemout 也是一个函数! 单独的函数是无法被叫做回调函数的,回调函数的概念是相互的。所以更确切的说法应该是:

首先这里的 箭头函数和匿名函数作为  setTimout 的参数, 然后在 setTimout 内部被调用,最后 箭头函数和匿名函数才被称为  setTimout 的回调函数。

4.我发现其实有很多新手是没有搞懂函数不同的声明方式,所以才导致你们迷惑的。我们这里先来讲一下函数常用的三种定义方式。

在这里虽然这三个函数的执行结果是一样的,但是它们的区别是不小的。使用 function 关键字声明一个函数。被叫做函数声明。 而下面的两种方法是被叫做函数表达式

5. 虽然在使用方法上我们都是通过 "()" 去调用,但是其实它们还是有差别的。其中最重要的一个差别就是,使用函数声明定义的一个函数,该变量会被 js 解析器提升到代码开始执行之前。而使用函数表达式定义的函数则不会被提升。什么意思呢?

你会发现,我们竟然可以在定义 hello 函数之前去使用这个函数。而下面两个函数都报出了在赋值之前调用的错误。

6. 在这里我们再延伸一个知识点。我们在定义 hello 函数之前,首先定义一个 变量 name


虽然这里看起来 name 是在 hello 函数之前声明的,但是 hello 这个变量的声明其实是在变量 name 之前的。

7. 其原因用简单的描述就是:js 解析器会在到你这个.js 文件后,会优先去查找使用 function 声明的函数名称,然后把这些函数名保存在一个对象中,并且提前创建一个引用来-->指向这个函数体。 具体细节还需读者自主查询,本文重点不在这里。

8. 如果你读懂了上面的几个环节,那么我觉得这种写法你同样应该明白了。


那么我们趁热打铁,开启下一篇章。

二. 数据处理方式

  1. 我们都知道函数是为了帮助我们完成一些复杂的逻辑运算,可以反复调用的,并且函数是可以传递参数的。

比如上面的函数,允许我们传递两个数字类型的变量,然后该函数会把这两个数字的和返回给我们。

2. ok,上面的内容很简单,我想大家应该都明白。如果我们日常和后端打交道的数据传输没有延迟,那么自然而然我们对数据处理起来就会非常方便。什么意思呢?假设我们 向后端发送请求获得数据 ,这一过程是一瞬间完成的,那么我们就可以顺着我们的想法从上往下写非常顺畅。

如上面刚写的的函数一样,你可以理解为我们向后端服务器请求了一个数据,数据一瞬间就返回了,那么们就可以把这个 data 给返回出去。然后在下面用一个变量去接受一下,随之进行一些运算。

3. 就如上一篇文章讲的那样。很遗憾的是,我们在进行一些可能需要一定时间才可以完成的任务的时候,不可能是同步完成的,因为一行代码而阻塞后面整段代码的执行是非常不可取的事情。

4. 这里我们来简单模拟一个场景。

我们定义了一个普通对象 data 来模拟后端即将传递给我们的数据。我们假设这个数据的可能需要花费 1s 的时间才能返回。我们可能自然而然的想到,那不是和之前一样嘛,在 setTimeout 里返回不就行了吗。

你可以先思考一下上面的这段代码,userData 会拿到正确的 data 值吗?

5. 非常遗憾的是,我们是无法在同步的代码里第一时间拿到异步函数的返回值的。

那么造成上面的代码结果的原因是为什么?为什么是 undefined 呢?我们一步一步分析。

三. 理清思路

  1. 当下面画黄线的代码被执行的时候。紧接着下一步我们就需要马上跳进 getData 的函数体中去分析。

2. 进到这个函数里,首先就是执行 setTimeout 函数。 (我在这里再再再亿次强调,setTimeout 本身就是一个普通函数,没什么特别的。)

3. 但是 setTimeout 函数会把接收的回调函数给推送到任务队列里去排队。什么?你没看见回调函数?这不就是文章最开头说的函数的声明方式之一箭头函数吗?怎么这么快就忘了?自觉翻回上面去再看一遍⏰。

4. 紧接着 getData函数 执行完毕,看一眼,函数本身没有返回值,那么默认返回值为 undefined

5. 这里需要特别注意! 我们如果在这里写了 return语句 ,这样才能算是 getData函数的 返回值。


而在我们的 data 却是 setTimout 的回调函数的返回值,你能拿到才怪。

6. 那怎么办呢?我们继续往下看。

四. 回调函数

  1. 别着急往下看,经过上面的三个环节,我们先做个小测试 。


上面这段代码你看懂了吗?(下面是执行结果)


如果你对执行结果不是特别清楚,没关系。到这一步我只希望你能读懂下面这行代码,至少对于写法上,很清楚的知道为什么可以这样写


如果你暂时还没搞懂,那么我强烈建议你至少回过头再品味一下第一个标题 函数,这次要细读。

2.如果你读懂了,恭喜你 ,你距离理解这个名词更近了一步。接下来我们稍微改造一下代码。

3.上面这段代码乍一看很玄乎,别着急,我们慢慢分析。首先 modifyData函数 是我们提前设定好的一个处理后端数据的函数。(前提是如果我们能拿到后端给我们的数据)

4.既然我们没有办法在同步函数里拿到 data 后再去处理,那么我们就干脆提前给后端代码函数 getData 一个参数。

一个我们提前设定好的处理函数。当  setTimeout 的回调函数拿到数据后,就帮我们执行这个函数,也就是  modifyData 函数。然后把  data 作为参数传递给  modifyData函数

5. 我们在  setTimout 的回调函数中打印一下修改前后的值。

6. 我们会发现,我们之后的代码都在回调函数里去处理的话,就能完美实现需求。也就是后端传过来的数据我们可以拿到了,并且可以处理成我们想要的数据了。

结语

在这里我们就先不引入解回调地狱的概念了了,我害怕都的读者确实会绕迷糊。 我会在放在手写 Promise 之前,引入这个概念。 希望读者可以细细体会上面的代码,一旦学会这些概念,你会看到和之前不一样的 js 世界 。

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

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

相关文章

校园论坛(Java)—— 数据报表模块

校园论坛(Java)—— 数据报表模块 文章目录校园论坛(Java)—— 数据报表模块1、写在前面2、系统结构设计2.1 各个页面之间的调用关系2.2.3、数据报表设计3.1 数据报表主界面的实现3.2 发表数Top5的普通帖子3.3 回帖数Top5的普通帖…

技术人员创业的第一步分析(续,可听音频)

概述:昨天的文章发布以后,在腾讯云TVP专家群里和多个技术群里都引起了一些讨论,基于这些讨论,有了今天的这篇续章。里面谈到了这次创业中,青润经历过的几次生死关头,是真的差点离开人世,而不是想…

2022年物联卡的发展前景如何

在这个万物互联的时代,针对于企业设备联网的物联卡就显得格外重要了,而共享单车,移动支付,智慧城市,自动售卖机等企业采购物联卡会面临着各种问题,低价陷阱,流量虚假,管理混乱&#…

JMeter 做性能测试,YYDS!

2. JMeter下载和安装 JMeter可以在JMeter的官方网站下载,下载链接如下图所示,xmeter君写本文的时候(2016/11)可以下载到的最新的版本是3.0。 下载后解压到你系统下的任意目录,我们称该目录为%JMETER_HOME%,…

Dart语言简介

简单介绍Dart语言 Dart是一种针对客户优化的语言,亦可在任何平台上快速开发的应用陈旭。 目标是为多平台开发提供最高效的变成语言,并为应用程序框架搭配了领会的运行时执行平台。 Dart特点 Dart语言 类型安全,使用静态型检查来确保变量的…

Linux命令之常用基础命令备查手册

一、前言 家里领导因公司系统部署国产化发展趋势,需要学习Linux。作为Linux初学者,希望能有一篇博文提供学习快速学习和掌握Linux系统的常用基础命令。为了满足领导要求,特编写此博文,尽量将常用Linux命令囊括进来,以示…

基于ssm的宠物商城网站设计与实现

项目描述 临近学期结束,还是毕业设计,你还在做java程序网络编程,期末作业,老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下,你想解决的问…

HTML5期末大作业:基于HTML+CSS+JavaScript实现中国风文化传媒企业官网源码

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…

【一条命令搞定rabbitmq的安装与配置】

提示:宝塔面板安装docker/docker-compose,一条命令搞定rabbitmq的安装与配置 文章目录前言一、docker-compose.yml配置二、安全组规则添加端口三、通过浏览器访问rabbitmq的管控页面总结前言 已经安装好了宝塔面板、并且可以在Docker栏目,选…

[附源码]计算机毕业设计物业管理系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

微服务框架 SpringCloud微服务架构 16 SpringAMQP 16.2 入门案例的消息发送

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构16 SpringAMQP16.2 入门案例的消息发送16.2.1 直接开干16.2.2 总结16 Spri…

八股文之算法

文章目录剑指offer链表1 从尾到头打印链表方案一:非递归方案二:递归方案三:普通数组存储方案三:递归2 链表反转方案一:使用栈解决方案二:双指针迭代方案三:递归3 反转链表一部分方法一&#xff…

Android 基础知识3-4 Activity的声明周期

引言: 在前面的几个例子中,我们发现所有集成Activity的类都重写了onCreate方法,程序运行就会自动进入这个方法。其实Activity类中还有很多类似onCreate的方法,比如onStart、onReaume、onPause、onDestroy等,而这些方法…

[黑马程序员C++笔记]P168-P173模板-函数模板

视频地址:黑马程序员匠心之作|C教程从0到1入门编程,学习编程不再难_哔哩哔哩_bilibili 目录 P167模板-模板的概念 P168模板-函数模板的基本语法 P169模板-函数模板的注意事项 P170模板-函数模板案例-数组排序 P171模板-普通函数与函数模板的区别 P172模板-普通…

Android 接口的default 方法运行时报错AbstractMethodError

【问题描述:接口default方法AbstractMethodError】 记录一个Android项目中遇到的问题,我们通过exclude方式重写了一个依赖,改用本地的实现,其中一个接口的default 方法,在运行时报错:AbstractMethodError&…

Mysql之存储引擎

目录 一、存储引擎概念 二、MyISAM的特点介绍 三.InnoDB特点 对比InnoDB和MyISAM 死锁 查看系统支持的存储引擎 查看表的使用存储引擎 修改存储引擎 一、存储引擎概念 MySQL中的数据用各种不同的技术存储在文件中,每一种技术都使用不同的存储机制、索引技巧…

sql serve数据库基础入门(2)

前言 🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言初阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>: 在上一篇的最后,牛牛介绍了怎么创建表,本篇牛牛介绍如…

【华为上机真题 2022】拼接URL

🎈 作者:Linux猿 🎈 简介:CSDN博客专家🏆,华为云享专家🏆,Linux、C/C、云计算、物联网、面试、刷题、算法尽管咨询我,关注我,有问题私聊! &…

Android-Jetpack Compose的简单运用

一.初步认识Jetpack Compose 1.什么是Jetpack Compose Jetpack Compose 是一个用于构建原生Android UI 的现代化工具包,它基于声明式的编程模型,因此你可以简单地描述UI的外观,而Compose则负责其余的工作-当状态发生改变时,你的…

端口转发工具Rinetd详细入门教程

目录 条件 下载 安装 方法A.shell安装 方法B.shell脚本安装 配置rinetd.conf文件 编辑器A:nano(新手友好) 编辑器B:vim rinetd开关 A.配置启动 B.脚本启动 创建脚本 启动 测试 参考链接 条件 有root权限rinetd.c…