前言

callback,大家都知道是回调函数的意思。如果让你举些callback的例子,我相信你可以举出一堆。但callback的概念你知道吗?你自己在实际应用中能不能合理利用回调实现功能? 我们在平时的学习中容易犯不去深究的病,功能实现了也就不再去追其原由,对一些概念模模糊糊。如果对callback没有一个清楚的理解,估计你在学习Node.js后会崩溃,因为callback是Node.js三大核心之一。

一 .回调函数

回调函数的概念

A callback is a function that is passed as an argument to another function and is executed after its parent function has completed.

以上是Google的解释,非常清晰简明,小编令人窒息的四级英语水平都能看懂。
下面给一个回调的例子

function doSomething(msg, callback){alert(msg);if(typeof callback == "function") callback();}
doSomething("回调函数", function(){alert("匿名函数实现回调!");});

我们再来看几个经典的回调函数代码,我保证你一定用过他们:

回调函数例子.png

从上面的例子,我们可以看出回调与同步、异步并没有直接的联系,回调只是一种实现方式,既可以有同步回调,也可以有异步回调,还可以有事件处理回调和延迟函数回调,这些在我们工作中有很多的使用场景。


二.把使用this对象的函数作为回调函数(陷阱)

当回调函数是一个使用this对象的函数时,我们必须改变执行回调函数的调用对象来保证this对象的上下文。在讲这个问题之前,我们必须先了解JS于this的指向。我们这里不详细谈这个问题,我直接说下自己学习过程总结的判断this指向的两条经验(既然是自己的经验,那就不一定对,希望大家指正):
(1)this的指向是在函数执行的时候确定的,在函数定义的时候是确定不了,实际上this的最终指向的是那个调用它的对象
(2)调用执行函数时,“.”前面是什么,this就是什么。前面没有对象,就是window了。(好粗暴)

回到使用this对象的函数作为回调函数这个问题,我们首先来看看下面这段代码:
//定义一个拥有一些属性和一个方法的对象 //我们接着将会把方法作为回调函数传递给另一个函数

var clientData = {id: 096545,fullName: "Not Set",//setUsrName是一个在clientData对象中的方法setUserName: function (firstName, lastName){this.fullName = firstName + " " + lastName;}
} function getUserInput(firstName, lastName, callback){//code .....//调用回调函数存储callback(firstName, lastName);
}getUserInput("Barack","Obama",clientData.setUserName);console.log(clientData.fullName);  //Not Setconsole.log(window.fullName);  //Barack Obama

在上面的代码中,当clientData.setUsername被执行时,this.fullName并没有设置clientData对象中的fullName属性。相反,它将设置window对象中的fullName属性,这是因为callback中的this指向window的缘故。

使用Call和Apply函数来改变this指向

我们可以使用Call或者Apply函数来解决上面你的问题。到目前为止,我们知道了每个Javascript中的函数都有两个方法:Call 和 Apply。这些方法被用来设置函数内部的this对象以及给此函数传递变量。
这里我们演示Apply函数实现,Call函数类似。(call接收的第一个参数为被用来在函数内部当做this的对象,传递给函数的参数被挨个传递。Apply函数的第一个参数也是在函数内部作为this的对象,然而最后一个参数确是传递给函数的值的数组。)

Apply函数:

//注意到我们增加了新的参数作为回调对象,叫做“callbackObj”
function getUserInput(firstName, lastName, callback ,callbackObj){//code .....callback.apply(callbackObj, [firstName, lastName]);
}getUserInput("Barack", "Obama", clientData.setUserName, clientData);console.log(clientData.fullName); //Barack Obama

使用Apply函数正确设置了this对象,我们现在正确的执行了callback并在clientData对象中正确设置了fullName属性


三.回调函数是实现异步编程的利器

在程序运行中,当某些请求过程漫长,我们有时没必要选择等待请求完成继续处理下一个任务,这时使用回调函数进行异步处理可以大大提高程序执行效率。例如:AJAX请求。若是使用回调函数进行处理,代码就可以继续进行其他任务,而无需空等。实际开发中,经常在javascript中使用异步调用!
下面有个使用AJAX加载XML文件的示例,并且使用了call()函数,在请求对象(requested object)上下文中调用回调函数。

function fn(url, callback){var httpRequest;    //创建XHRhttpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :   //针对IE进行功能性检测window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : undefined;httpRequest.onreadystatechange = function(){if(httpRequest.readystate === 4 && httpRequest.status === 200){  //状态判断callback.call(httpRequest.responseXML); }};httpRequest.open("GET", url);httpRequest.send();
}fn("text.xml", function(){    //调用函数console.log(this);                 / /此语句后输出
});console.log("this will run before the above callback.");  //此语句先输出

我们请求异步处理,意味着我们开始请求时,就告诉它们完成之时调用我们的函数。在实际情况中,onreadystatechange事件处理程序还得考虑请求失败的情况,这里我们是假设xml文件存在并且能被浏览器成功加载。这个例子中,异步函数分配给了onreadystatechange事件,因此不会立刻执行。
最终,第二个console.log语句先执行,因为回调函数直到请求完成才执行。

在Javascript编程中回调函数经常以几种方式被使用,尤其是在现代web应用开发以及库和框架中:

  • 异步调用(例如读取文件,进行HTTP请求,动态加载js文件,加载iframe资源后,图片加载完成执行回调等等)
  • 事件监听器/处理器
  • setTimeout和setInterval方法
  • 一般情况:精简代码

4.“回调地狱”问题以及解决方案

这么多回调嵌套,我还没遇到过。下面内容是直接从网上copy过来,大家看下,还是很好理解的。
在执行异步代码时,无论以什么顺序简单的执行代码,经常情况会变成许多层级的回调函数堆积以致代码变成下面的情形。这些杂乱无章的代码叫做回调地狱因为回调太多而使看懂代码变得非常困难。我从node-mongodb-native,一个适用于Node.js的MongoDB驱动中拿来了一个例子。这段位于下方的代码将会充分说明回调地狱:

var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), {'pk':CustomPKFactory});p_client.open(function(err, p_client) {p_client.dropDatabase(function(err, done) {p_client.createCollection('test_custom_key', function(err, collection) {collection.insert({'a':1}, function(err, docs) {collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) {cursor.toArray(function(err, items) {test.assertEquals(1, items.length);// Let's close the dbp_client.close();});});});});});});

你应该不想在你的代码中遇到这样的问题,当你当你遇到了-你将会是不是的遇到这种情况-这里有关于这个问题的两种解决方案。

给你的函数命名并传递它们的名字作为回调函数,而不是主函数的参数中定义匿名函数。
模块化L将你的代码分隔到模块中,这样你就可以到处一块代码来完成特定的工作。然后你可以在你的巨型应用中导入模块。

作者:echozzh
链接:https://www.jianshu.com/p/84cc8732689c
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

JavaScript中的回调函数(callback)相关推荐

  1. 理解javascript中的回调函数(callback)【转】

    在JavaScrip中,function是内置的类对象,也就是说它是一种类型的对象,可以和其它String.Array.Number.Object类的对象一样用于内置对象的管理.因为function实 ...

  2. 理解javascript中的回调函数(callback)

    理解javascript中的回调函数(callback) 在JavaScrip中,function是内置的类对象,也就是说它是一种类型的对象,可以和其它String.Array.Number.Obje ...

  3. 关于javascript中的回调函数

    关于javascript中的回调函数 原文地址:http://blog.csdn.net/sicluoyi/article/details/1737969 考虑一个这样的例子: 假如某个项目的底层和高 ...

  4. 理解与使用Javascript中的回调函数

    在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被"存储"在变量中,能作为函数参数被传递,能在函数中被创建, ...

  5. 【JavaScript】理解与使用Javascript中的回调函数

    在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被"存储"在变量中,能作为函数参数被传递,能在函数中被创建, ...

  6. 什么是JavaScript中的回调函数?

    This article gives a brief introduction to the concept and usage of callback functions in the JavaSc ...

  7. bootstraptable 加载完成回调函数_牛皮了!头一次见有大佬把「JavaScript中的回调函数」详解得如此清晰明了...

    前言 callback,大家都知道是回调函数的意思.但是你对这个概念应该是模模糊糊.比如Ajax,你只知道去调用返回函数,如果对callback没有理解清楚,估计你在学习Node.js后会崩溃,因为c ...

  8. javaScript中的回调函数

    ​ <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8&qu ...

  9. 浅聊JavaScript中的回调函数

    Time will tell. 一.JavaScript中的函数 在 JavaScript 中,函数也是一种 data,一种数据,只不过这种数据比较特殊,它里面存的是代码,而且这种data可以被调用执 ...

最新文章

  1. 微软发布新的Azure Pipelines功能和集成
  2. C++_系列自学课程_第_9_课_C语言风格字符串_《C++ Primer 第四版》
  3. 判断回文(Python)
  4. python学习-数据类型(列表→创建、取值、大小、长度)
  5. jzoj6344-[NOIP2019模拟2019.9.7]Huge Counting【组合数,状压dp】
  6. IEEE 回应禁止华为系审稿人;Wi-Fi 联盟等恢复华为成员资格;Angular 8 正式发布 | 极客头条...
  7. 贯穿时域与频域的方法——傅立叶分析
  8. 安装搭建zimbra邮件服务器(dns域名解析)
  9. LINUX下载编译ass
  10. 给“网吧”做管理系统
  11. 从零开始学PCR技术(一):PCR技术简介
  12. 双引号在python中什么意思_Python中单引号和双引号的作用
  13. frm文件导入mysql_.frm文件怎么导入到数据库
  14. 求助计算机程序员,程序员用代码求救:几近绝望时竟是老本行救了他
  15. Python漫画爬虫开源 66漫画 AJAX,包含数据库连接,图片下载处理
  16. Linux下vi命令编辑器怎样编辑,怎样保存退出
  17. CTFshow-吃鸡杯-RE
  18. oracle 标示符太长,Oracle PLS-00114: 标识符 ' ' 太长
  19. 国内外程序员常去的九大网站
  20. 简单的Web日志分析

热门文章

  1. [html] 页面上的登录表单记住了密码(显示星号),但我又忘了密码,如何找回这个密码呢?
  2. 工作393-注册小程序
  3. [css] 请用css写一个扫码的加载动画图
  4. 前端学习(2491):refused to apply style from ‘‘ because its MIME type (‘text/html‘) is not a supported sty
  5. “约见”面试官系列之常见面试题第三篇说说常用的es6语法(建议收藏)
  6. 前端学习(2137):webpack的介绍和安装
  7. 前端学习(662):逻辑运算符练习
  8. 前端学习(531):什么是等高布局
  9. 第十九期:HTTPS虐我千百遍,我却待她如初恋!
  10. 深入理解移动前端开发之viewport