JavaScript基础——回调(callback)是什么?

2023-11-12

上篇文章《JavaScript基础——你真的了解JavaScript吗?》,我们明白了JavaScript是一个单线程、非阻塞、异步、解释性语言,清楚了什么是单线程、进程、阻塞、调用堆栈、异步回调、任务循环等概念,没看的或者不清楚的建议点击《JavaScript基础——你真的了解JavaScript吗?》再看一遍,只有理解了,才能轻松阅读理解本篇文章内容。

640?wx_fmt=png

什么是callback?

640?wx_fmt=png

JavaScript 是单线程工作,这意味着两段脚本不能同时运行,而是必须一个接一个地运行。我们人类是多线程工作。您可以使用多个手指打字,可以一边开车一边与人交谈。唯一一个会妨碍我们的是打喷嚏,因为当我们打喷嚏的时候,所有当前进行的活动都必须暂停。这真是非常讨厌,尤其是当您在开车并想与人交谈时。您可不想编写像打喷嚏似的代码。JavaScript由于单线程限制,防止阻塞,只能通过异步函数的调用方式,把需要延迟处理的事件放入事件循环队列。到目前为止,回调是编写和处理JavaScript程序异步逻辑的最常用方式。说了这么多,既然回调这么重要,到底什么是回调(callback)呢?

简单的定义:回调就是一个在另外一个函数执行完后要执行的函数

复杂的定义:在JavaScript中,函数是对象。因此函数可以将函数作为参数,并且可以由其他函数进行返回。执行此操作的函数称为高阶函数。任何作为参数传递的函数都称为回调函数。

640?wx_fmt=png

为什么需要回调?

640?wx_fmt=png

开篇已经介绍了JavaScript是单线程的,需要通回调函数处理异步相关的逻辑,理论还是过于生硬,我们还是来看段代码吧:

function first(){
   console.log(1);
}
function second(){
   console.log(2);
}
first();
second();

正如你所料,先执行first函数,再执行second函数,控制台将输出以下内容:

1
2

目前看来没什么问题,如果first()函数中含有某种无法立即执行的函数呢?例如,我们必须发送请求然后等待结果响应的API请求?为了模拟API请求,我们可以使用setTimeout函数模拟。我们将函数延迟500毫秒来模拟请求,我们更改后代码如下:

function first(){
   // Simulate a code delay
   setTimeout( function(){
       console.log(1);
   }, 500 );
}
function second(){
   console.log(2);
}
first();
second();

我们将 console.log(1) 延迟500毫秒输出,这段代码会怎么输出呢?

2
1

我们希望的顺序先执行first,再执行second,但是由于JavaScript是异步的,所有的延迟处理都要放入循环队列里,因此事与愿违,不能按照我们的希望顺序输出。如果希望这段代码按照我们的意愿输出,我们可以使用回调函数,确保某些代码执行完了,再执行另外一段代码。

640?wx_fmt=png

创建一个简单的回调

640?wx_fmt=png

说了这么多,让我们创建一个简单的回调!

我们打开编辑器,先输入如下代码:

function doHomework(subject) {
   alert(`Starting my ${subject} homework.`);
}

上面我们创建了doHomeWork的函数,我们接受一个变量,通过控制台调用,将得到下面的提示:

doHomework('math');
// Alerts: Starting my math homework.

接着,我们开始添加回调,在doHomework函数中添加一个参数callback,然后在第二个参数中回调我们定义的函数。代码如下:

function doHomework(subject, callback) {
   alert(`Starting my ${subject} homework.`);
   callback();
}
doHomework('math', function() {
   alert('Finished my homework');
});

正如你希望的,我们在控制台里运行上述代码,将会受到两个连续的alert,Starting my math homework,然后弹出 Finished my homework。

但是回调函数并不是非得在调用函数中定义,我们可以单独定义,修改后的代码如下:

function doHomework(subject, callback) {
   alert(`Starting my ${subject} homework.`);
   callback();
}
function alertFinished(){
   alert('Finished my homework');
}
doHomework('math', alertFinished);

此示例的输出结果和上段代码的结果一致,我们实现了在doHomework函数中调用alertFinished,实现了函数作为参数进行传递,实现了回调函数的创建。

640?wx_fmt=png

用回调编写真实业务场景!

640?wx_fmt=png

例如我们有一个需求,用NodeJs实现从论坛帖子列表数据中显示其中的一个帖子的信息及留言列表信息,代码如下:

DB/posts.json(帖子列表数据)

[
   {
       "id": "001",
       "title": "Greeting",
       "text": "Hello World",
       "author": "Jane Doe"
   },
   {
       "id": "002",
       "title": "JavaScript 101",
       "text": "The fundamentals of programming.",
       "author": "Alberta Williams"
   },
   {
       "id": "003",
       "title": "Async Programming",
       "text": "Callbacks, Promises and Async/Await.",
       "author": "Alberta Williams"
   }
]

DB/comments.json(评论列表)

[
   {
       "id": "phx732",
       "postId": "003",
       "text": "I don't get this callback stuff."
   },
   {
       "id": "avj9438",
       "postId": "003",
       "text": "This is really useful info."
   },
   {
       "id": "gnk368",
       "postId": "001",
       "text": "This is a test comment."
   }
]

Index.js

const fs = require('fs');
const path = require('path');
const postsUrl = path.join(__dirname, 'db/posts.json');
const commentsUrl = path.join(__dirname, 'db/comments.json');
//return the data from our file
function loadCollection(url, callback) {
   fs.readFile(url, 'utf8', function(error, data) {
       if (error) {
           console.log(error);
       } else {
           return callback(JSON.parse(data));
       }
   });
}
//return an object by id
function getRecord(collection, id, callback) {
   var collectobj=collection.find(function(element){
       return element.id == id;
   });
   callback(collectobj);
   return collectobj;
}
//return an array of comments for a post
function getCommentsByPost(comments, postId) {
   return comments.filter(function(comment){
       return comment.postId == postId;
   });
}
loadCollection(postsUrl, function(posts){
   loadCollection(commentsUrl, function(comments){
       getRecord(posts, "001", function(post){
           const postComments = getCommentsByPost(comments, post.id);
           console.log(post);
           console.log(postComments);
       });
   });
});

大家请注意,在loadCollection函数中小编没有使用try/catch捕捉异常,使用的是if/else,因为catch无法从readFile方法中获取异常。上述代码还需要完善,我没有包含任何错误处理。如果在任何步骤中发生错误,程序将无法继续。

错误处理是很重要的事情,我们写代码时要认证严格对待,比如我们要编写一个用户登录的功能。涉及从网页表单里获取用户名和密码,查询我们的数据库,确认用户信息是否正确,验证通过后,将用户引导到用户中心页面。如果用户名密码格式不正确,用户名密码不正确,我们应该将错误信息返回给用户,并引导用户重新登录。

640?wx_fmt=png

很好!我们一起把回调的内容学完了,理解了什么是回调,异步编程是我们的代码中使用的一种方法,用于推迟事件以便以后执行。当您处理异步任务时,回调是一种解决方案,以便它们按顺序执行。


如果我们有多个任务依赖于前几个任务的结果,那我们就要使用多个嵌套回调,但是就会引发“回调地狱”(过多的回调嵌套会使得代码变得难以理解与维护),还好Promise解决了“回调地狱”的问题,让我们以同步的方式编写代码,小编将会在下篇文章里详细介绍Promise,敬请期待!

注:本文内容参考

Brandon Morelli https://codeburst.io/javascript-what-the-heck-is-a-callback-aba4da2deced

Alberta Williams https://code.tutsplus.com/tutorials/javascript-callbacks-promises-and-async-functions-part-1--cms-30000?_ga=2.97423583.1776052358.1543636348-289309391.1524575295

专注分享当下最实用的前端技术。关注前端达人,与达人一起学习进步!

长按关注"前端达人"

640?wx_fmt=gif 640?wx_fmt=jpeg
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript基础——回调(callback)是什么? 的相关文章

  • 花旗金融2020春招面经(offer)

    面试刚开始是英文自我介绍 英文介绍项目 英文交流几个问题 接着是Java基础知识 数据库知识 面试官很好 很多问题并不会太为难你 还会询问你的工作意向 面完大概3天就来了offer 面试问题和答案主要整理如下 Java集合类 collect
  • 基于KNN-Dense sift的图像识别(手势识别)

    K 近邻算法 KNN 原理 最简单最初级的分类器是将全部的训练数据所对应的类别都记录下来 当测试对象的属性和某个训练对象的属性完全匹配时 便可以对其进行分类 但是存在一些问题 如不可能所有测试对象都会找到与之完全匹配的训练对象 其次就是存在
  • 解决vue3中 import type { FormInstance } from ‘element-plus‘出现报错

    前言 在使用element plus的form表单组件时 引入FormInstance类型 结果出现以下错误 模块 element plus 没有导出的成员 FormInstance 你是想改用 import FormInstance fr
  • upload(pass01~pass09)

    文章目录 Pass 01 Pass 02 Pass 03 Pass 04 未解决 Pass 05 失败 自己的一些尝试 后续 Pass 06 Pass 07 Pass 08 Pass 09 Pass 01 先查看提示 在客户端使用JS对图片
  • 树莓派教程 - 1.4 树莓派GPIO库wiringPi 树莓派串口ttyS0

    Git例程源码仓库 https github com ZhiliangMa raspberry git 使用树莓派的串口前 需要先了解树莓派板载的两个串口的区别 树莓派3为了增加蓝牙硬件 将独立时钟的硬件串口 dev ttyAMA0 默认分
  • 中国数字新商业发展洞察报告 附下载地址

    2019年中国数字经济规模达到35 8万亿元 同比名义增长率相比GDP高出6 7 在经济下行压力加大 外部环境复杂叠加疫情冲击的特殊时期 围绕数字经济开展新一轮科技革命与产业变革 无疑是引领经济内生动力增长 结构优化的关键 产业数字化规模占
  • 把PHP添加到IIS

    把PHP添加到IIS 把PHP添加到IIS 首先将PHP配置环境 打开IIS服务 结尾 把PHP添加到IIS 首先将PHP配置环境 首先去官网将PHP给下载下来 https www php net 然后将PHP下载的安装包里面的文件给解压到
  • 浅谈K-means算法和实现(基于Python)

    Kmeans可视化 https www naftaliharris com blog visualizing k means clustering K means原理 K means 有一个著名的解释 牧师 村民模型 有四个牧师去郊区布道
  • MYSQL七种关系图

    MYSQL七种查询关系 CREATE TABLE t blog id INT PRIMARY KEY AUTO INCREMENT title VARCHAR 50 typeId INT SELECT FROM t blog id titl
  • C/C++白盒测试系列之Cppcheck使用介绍(一)

    工具简介 下载安装 Linux 官方网址 http sourceforge net projects cppcheck 安装方式 解压后 直接make进行编译 完成后 make install进行安装 验证安装 cppcheck v 查看是
  • 删除msconfig 项目

    regeditHKEY LOCAL MACHINE SOFTWARE Microsoft Shared Tools MSConfig startupreg 转载于 https www cnblogs com kevinkim archive
  • qt5.10.1安装

    首先下载qt5 10 1 网址 http download qt io archive qt 可以找到5 10 1之后进行下载 可以发现只有x86的 实际上64位的也是都包括在里面的 安装的时候可以进行选择版本的 下载好之后进行安装 qt比
  • 二十三.Python学习笔记.5

    组合数据类型 一 集合类型及操作 1 集合是多个 元素的无序组合 集合类型与数学中的集合概念一致 集合元素之间无序 每个元素唯一 不存在相同元素 集合元素不可更改 不能是可变数据类型 2 集合是多个元素的无序组合 集合用大括号 表示 元素间
  • UEditor百度富文本编辑器实现自定义按钮和自定义右键菜单

    以1 5 0版本为例子 注意 所有字符串的字母只能小写 不能大写 自定义工具栏按钮 在根目录的ueditor config js找到toolbars参数 大于34行 在后面加上自定义字符串 然后在根目录 lang zh cn zh cn j
  • Word2016怎么制作目录

    Word2016如何制作目录 点击 引用 点击 目录 选择目录的生成方式
  • 实体类与实体DTO类之间的转换

    实体类与实体DTO类之间的转换 实体类与实体DTO类之间的转换 1 通过使用第三方序列化反序列化工具Newtonsoft Json 2 通过反射实现 3 通过表达式目录树加字典缓存实现 4 通过表达式目录树加泛型缓存实现 静态构造函数 1
  • 解决redis缓存雪崩

    目录 一 什么是缓存雪崩 二 解决缓存雪崩 一 什么是缓存雪崩 1 同一时间大量的key同时失效或者redis宕机 大量请求直接访问数据库 二 解决缓存雪崩 1 如果是同一时间大量key失效 可以给不同的key的ttl添加随机值 2 如果是
  • Python 处理GBK编码转UTF-8读写乱码问题

    今日写了个爬虫 爬取前程无忧的招聘信息 老套路 首先获取网页源代码 coding utf 8 import requests url http search 51job com jobsearch search result php pag
  • cmake+QT+VTK常见错误及解决方法

    1 安装环境 cmake3 0 QT4 8 6 VTK5 10 PS VTK6 10以上只能配合使用QT5 0以上版本 2 编译安装 参考 http blog csdn net www doling net article details
  • 从那里进入EI检索号查询入口?

    一 EI检索号是什么 EI检索号是就是文章被EI收录后 在检索页面生成的一串数字 EI检索号样式 Accession number 20200308040970 这串数字是唯一的 EI检索收录与否 也就是看有无这串数字 后期如果去申请EI检

随机推荐

  • 5G QoS控制原理专题详解-基础概念

    相关文章会在公众号同步更新 公众号 5G通信大家学 持续更新的相关5G内容都是直接根据3GPP整理 保证更新内容的准确性 避免通过二手 甚至多手的资料 以讹传讹误导网友 在介绍完流程详解后 会整理专题内容 比如切片 服务发现 QoS流端到端
  • Spring Cloud Sleuth使用简介

    Spring Cloud Spring Cloud为开发者提供了在分布式系统 如配置管理 服务发现 断路器 智能路由 微代理 控制总线 一次性Token 全局锁 决策竞选 分布式会话和集群状态 操作的开发工具 使用SpringCloud开发
  • VS2008如何打开memory窗口

    VS2008如何打开memory窗口 1 在想要观察的变量处设置断点 2 运行工程至断点处 3 debug gt windows gt memory 4 将变量名称复制至memory的address处 按enter键即可 5 右击内存显示去
  • klee内存模型

    klee内存模型 一 LLVM基础 二 Klee中相关的类 2 1 基础类 2 2 内存管理相关类 三 示例 3 1 示例1 3 2 示例2 3 3 示例3 3 4 示例4 这篇blog主要通过一些简单的示例来了解以下klee对内存的建模方
  • JAVA生成带图标的二维码(产品溯源码)

    一 效果图 二 代码示例 1 引入依赖
  • element-ui组件库

    PC端组件库参考 https www jianshu com p 669d3e41dca6 element 官网 https element eleme cn zh CN 1 下载安装组件库 cnpm i element ui 2 两种引入
  • wx.getUserProfile调用后没有反应?获取不到真正的用户头像和昵称

    考虑到近期开发者对小程序登录 用户信息相关接口调整的相关反馈 为优化开发者调整接口的体验 小程序登录 用户信息相关接口调整说明 公告中关于小程序回收 wx getUserInfo 接口可获取用户授权的个人信息能力的截止时间调整至2021年4
  • 基于Java的停车场管理系统的设计与实现

    技术 Java JSP等 摘要 随着科技的迅速发展 各种管理系统已应用到社会的各个领域 各个大小企业 单位 都充分意识到传统的手工管理模式已经逐渐不能适应时代的发展 为了更好的发展 纷纷开发适合自己的管理系统 通过停车场管理系统这个平台 可
  • ppp协议帧格式

    ppp协议帧格式解析 现在全世界使用得最多的数据链路层协议是 点对点协议 PPP Point to Point Protocol 用户使用拨号电话线接入因特网时 一般都是使用 PPP 协议 PPP 的帧格式和 HDLC 的相似 标志字段F
  • Idea中JRebel热部署安装及激活

    一 JRebel安装 到idea的插件下载中下载JRebel插件 二 JRebel激活 下载反向代理软件地址 Release v1 4 ilanyu ReverseProxy GitHub UUID生成地址 Online UUID Gene
  • 通过服务器接口上传文件,云服务器上传文件的接口

    云服务器上传文件的接口 内容精选 换一换 华为云帮助中心 为用户提供产品简介 价格说明 购买指南 用户指南 API参考 最佳实践 常见问题 视频帮助等技术文档 帮助您快速上手使用华为云服务 安装传输工具在本地主机和Windows云服务器上分
  • MQTT.fx客户端MQTT接入阿里云物联网平台,登录、订阅、发布消息

    目录 1 准备 2 MQTT fx 设置登录名 密码 3 MQTT fx 接入阿里云 订阅Topic 4 阿里云下发数据给 MQTT fx 5 MQTT fx 发布消息给服务器 相关链接 MQTT协议 1 准备 阿里云物联网 创建产品 设备
  • 01:STM32点灯大师和蜂鸣器

    目录 一 点亮1个LED 1 连接图 2 函数介绍 3 点灯代码 二 LED闪烁 1 函数介绍 2 闪烁代码 三 LED流水灯 1 连接图 2 函数介绍 3 流水灯代码 四 按键控制LED 1 电路图 2 连接图 3 函数介绍 4 按键控制
  • spring3在jboss4中部署异常java.lang.RuntimeException: XPathFactory#newInstance() failed

    java lang RuntimeException XPathFactory newInstance failed to create an XPathFactory for the default object model http j
  • vscode 配置C++编译环境(完美版)

    文章目录 vscode c 环境配置 完整教程请查看该教程 vscode c 环境配置 完整教程请查看该教程 https blog csdn net qq 43041976 article details 100542557 使用MinGW
  • 通过less或者scss 定义变量 实现 vue主题切换

    更新 不需要全局引入less或者scss的可以直接在body上面挂载css变量 body baseColor 4F94FA activeColor 4F94FA fontColor 4F94FA 然后在需要使用的地方 title color
  • python 深拷贝和浅拷贝浅析

    简单点说 1 copy copy 浅拷贝 只拷贝父对象 不会拷贝对象的内部的子对象 id会变化2 copy deepcopy 深拷贝 拷贝对象及其子对象 id会变化 gt gt gt import copy gt gt gt a 1 2 3
  • WAV文件格式解析

    来源 http www codeguru com cpp g m multimedia audio article php c8935 PCM Audio and Wave Files htm page 1 源程序下载地址 http www
  • 算法可视化该怎么实现

    算法可视化通常是指将算法的运行过程或结果以图像 动画或交互式图形的形式呈现出来 使得更容易理解和观察 要实现算法可视化 需要使用特定的工具或库 如 图像可视化 可以使用 Python 中的 matplotlib 库或者 JavaScript
  • JavaScript基础——回调(callback)是什么?

    上篇文章 JavaScript基础 你真的了解JavaScript吗 我们明白了JavaScript是一个单线程 非阻塞 异步 解释性语言 清楚了什么是单线程 进程 阻塞 调用堆栈 异步回调 任务循环等概念 没看的或者不清楚的建议点击 Ja