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

什么是callback?

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

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

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

为什么需要回调?

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

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

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

12

目前看来没什么问题,如果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毫秒输出,这段代码会怎么输出呢?

21

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

创建一个简单的回调

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

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

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,实现了函数作为参数进行传递,实现了回调函数的创建。

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

例如我们有一个需求,用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 filefunction 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 idfunction 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 postfunction 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方法中获取异常。上述代码还需要完善,我没有包含任何错误处理。如果在任何步骤中发生错误,程序将无法继续。

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

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

如果我们有多个任务依赖于前几个任务的结果,那我们就要使用多个嵌套回调,但是就会引发“回调地狱”(过多的回调嵌套会使得代码变得难以理解与维护),还好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

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

长按关注"前端达人"

JavaScript基础——回调(callback)是什么?相关推荐

  1. Web前端-JavaScript基础教程上

    Web前端-JavaScript基础教程 将放入菜单栏中,便于阅读! JavaScript是web前端开发的编程语言,大多数网站都使用到了JavaScript,所以我们要进行学习,JavaScript ...

  2. JavaScript基础15-day17【BOM(Navigator、History、Location)、定时器、切换图片练习、轮播图】

    学习地址: 谷粒学院--尚硅谷 哔哩哔哩网站--尚硅谷最新版JavaScript基础全套教程完整版(140集实战教学,JS从入门到精通) JavaScript基础.高级学习笔记汇总表[尚硅谷最新版Ja ...

  3. JavaScript基础14-day16【事件委派、事件绑定、事件传播、滚轮事件、键盘事件、键盘移动div】

    学习地址: 谷粒学院--尚硅谷 哔哩哔哩网站--尚硅谷最新版JavaScript基础全套教程完整版(140集实战教学,JS从入门到精通) JavaScript基础.高级学习笔记汇总表[尚硅谷最新版Ja ...

  4. JavaScript 基础知识 - BOM篇

    前言 本篇文章是JavaScript基础知识的BOM篇,如果前面的<JavaScript基础知识-DOM篇>看完了,现在就可以学习BOM了. 注意: 所有的案例都在这里链接: 提取密码密码 ...

  5. javascript基础修炼(4)——UMD规范的代码推演

    javascript基础修炼(4)--UMD规范的代码推演 1. UMD规范 地址:https://github.com/umdjs/umd UMD规范,就是所有规范里长得最丑的那个,没有之一!!!它 ...

  6. Javascript基础知识之四(常用数组方法)

    一.MDN链接 Array - JavaScript | MDNJavaScript的 Array 对象是用于构造数组的全局对象,数组是类似于列表的高阶对象.https://developer.moz ...

  7. JavaScript基础知识与脚本语言总结

    1 Aptana插件安装 1.Aptana插件安装 <1>Aptana是一个非常强大,开源,JavaScript-focused的AJAX开发IDE. <2>它的特点包括: J ...

  8. 002 - new javascript 基础

    002 - new javascript 基础 ####★技巧★ JS 引入 返回 从哪来到哪去 <script src="javascript:history.go(-1)" ...

  9. JavaScript 基础入门

    JavaScript 基础入门 简介 一.JS 基础语法 1.JS 语法与变量 (1)JavaScript 的书写位置 (2)认识输入输出语句 (3)学会处理报错 (4)变量 (5)变量声明提升 2. ...

最新文章

  1. 做事先做人 --- 我的十三条军规
  2. python 字符串的一些方法
  3. 远程连接MySQL数据库失败
  4. POJ 1664 把苹果
  5. union all会影响性能吗_哪些因素会影响悬臂式掘进机的性能?
  6. 计算机网络之应用层:1、概述
  7. 小米发布2021年第二季度财报:小米手机二季度平均售价1116.7元
  8. 连锁百货企业数据系统整理解决方案
  9. Qt环境下利用opencv逐帧播放视频
  10. 爆笑区块链段子送给你~
  11. JAVA:货币金额类型、精确小数类型数值的定义BigDecimal和基本运算操作
  12. [附源码]计算机毕业设计Python架构的博客平台设计(程序+源码+LW文档)
  13. Ubuntu 16.04+CUDA8.0+Caffe+OpenCV3.1
  14. matlab与python语法区别(持续更新)
  15. sas入门-笔记4 描述性统计分析
  16. 天云数据:去伪求真 国产数据库必须摒弃拿来主义
  17. 我讨厌慢节奏工作,我喜欢充实生活
  18. clamav病毒检测工具的使用
  19. 软件测试工程师薪资调查
  20. R语言通过在函数中设置na.rm=TRUE参数、在计算和分析中删除缺失值获得有效的计算结果(Excluding Missing Values from Analyses)

热门文章

  1. Java 快速排序法
  2. UBT9:ubuntu安装maven
  3. VMware中CentOS7虚拟机配置静态IP
  4. python3 字符串比较函数_python3.7字符串基本函数
  5. 并非从0开始的c++ day15
  6. python自动抓包_burp抓包+python定时签到
  7. JavaWeb之前后端分离的三步骤
  8. java mq_java实现MQ消息收发两种方式
  9. 石头剪刀布python代码_Python之石头剪刀布小游戏(史上最详细步骤)
  10. 分治法:线性时间选择