浅析JavaScript回调函数应用


Posted in Javascript onMay 22, 2016

一、回调函数定义

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。因此callback 不一定用于异步,一般同步(阻塞)的场景下也经常用到回调,比如要求执行某些操作后执行回调函数。

例子

一个同步(阻塞)中使用回调的例子,目的是在func1代码执行完成后执行func2。

var func1=function(callback){
  //do something.
  (callback && typeof(callback) === "function") && callback();
}
func1(func2);
  var func2=function(){
}

二、回调函数的使用场合

资源加载:动态加载js文件后执行回调,加载iframe后执行回调,ajax操作回调,图片加载完成执行回调,AJAX等等。
DOM事件及Node.js事件基于回调机制(Node.js回调可能会出现多层回调嵌套的问题)。
setTimeout的延迟时间为0,这个hack经常被用到,settimeout调用的函数其实就是一个callback的体现
链式调用:链式调用的时候,在赋值器(setter)方法中(或者本身没有返回值的方法中)很容易实现链式调用,而取值器(getter)相对来说不好实现链式调用,因为你需要取值器返回你需要的数据而不是this指针,如果要实现链式方法,可以用回调函数来实现
setTimeout、setInterval的函数调用得到其返回值。由于两个函数都是异步的,即:他们的调用时序和程序的主流程是相对独立的,所以没有办法在主体里面等待它们的返回值,它们被打开的时候程序也不会停下来等待,否则也就失去了setTimeout及setInterval的意义了,所以用return已经没有意义,只能使用callback。callback的意义在于将timer执行的结果通知给代理函数进行及时处理。

三、函数也是对象

想弄明白回调函数,首先的清楚地明白函数的规则。在javascript中,函数是比较奇怪的,但它确确实实是对象。确切地说,函数是用Function()构造函数创建的Function对象。Function对象包含一个字符串,字符串包含函数的javascript代码。假如你是从C语言或者java语言转过来的,这也许看起来很奇怪,代码怎么可能是字符串?但是对于javascript来说,这很平常。数据和代码之间的区别是很模糊的。

//可以这样创建函数
var fn = new Function("arg1", "arg2", "return arg1 * arg2;");
fn(2, 3);  //6

这样做的一个好处,可以传递代码给其他函数,也可以传递正则变量或者对象(因为代码字面上只是对象而已)。

传递函数作为回调

很容易把一个函数作为参数传递。

function fn(arg1, arg2, callback){
  var num = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
  callback(num);//传递结果
}

fn(10, 20, function(num){
  console.log("Callback called! Num: " + num); 
});//结果为10和20之间的随机数

可能这样做看起比较麻烦,甚至有点愚蠢,为何不正常地返回结果?但是当遇上必须使用回调函数之时,你也许就不这样认为了!

别挡道

传统函数以参数形式输入数据,并且使用返回语句返回值。理论上,在函数结尾处有一个return返回语句,结构上就是:一个输入点和一个输出点。这比较容易理解,函数本质上就是输入和输出之间实现过程的映射。

但是,当函数的实现过程非常漫长,你是选择等待函数完成处理,还是使用回调函数进行异步处理呢?这种情况下,使用回调函数变得至关重要,例如:AJAX请求。若是使用回调函数进行处理,代码就可以继续进行其他任务,而无需空等。实际开发中,经常在javascript中使用异步调用,甚至在这里强烈推荐使用!

下面有个更加全面的使用AJAX加载XML文件的示例,并且使用了call()函数,在请求对象(requested object)上下文中调用回调函数。

function fn(url, callback){
  var httpRequest;
//创建XHR
  httpRequest = window.XMLHttpRequest ? new XMLHttpRequest() :
 


  window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP"       ) : undefined;//针对IE进行功能性检测

  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语句先执行,因为回调函数直到请求完成才执行。

上述例子不太易于理解,那看看下面的示例:

function foo(){
  var a = 10;
  return function(){
    a *= 2;
    return a;    
  };  
}
var f = foo();
f(); //return 20.
f(); //return 40.

函数在外部调用,依然可以访问变量a。这都是因为javascript中的作用域是词法性的。函数式运行在定义它们的作用域中(上述例子中的foo内部的作用域),而不是运行此函数的作用域中。只要f被定义在foo中,它就可以访问foo中定义的所有的变量,即便是foo的执行已经结束。因为它的作用域会被保存下来,但也只有返回的那个函数才可以访问这个保存下来的作用域。返回一个内嵌匿名函数是创建闭包最常用的手段。

以上就是本文的全部内容,希望对大家学习javascript程序设计有所帮助。

Javascript 相关文章推荐
Javascript----文件操作
Jan 18 Javascript
JS实现OCX控件的事件响应示例
Sep 17 Javascript
纯JavaScript实现的分页插件实例
Jul 14 Javascript
Angular发布1.5正式版,专注于向Angular 2的过渡
Feb 18 Javascript
基于jquery插件实现拖拽删除图片功能
Aug 27 Javascript
JavaScript中全选、全不选、反选、无刷新删除、批量删除、即点即改入库(在yii框架中操作)的代码分享
Nov 01 Javascript
基于AGS JS开发自定义贴图图层
Mar 31 Javascript
webpack配置的最佳实践分享
Apr 21 Javascript
vuejs如何配置less
Apr 25 Javascript
JavaScript中工厂函数与构造函数示例详解
May 06 Javascript
js实现无缝轮播图
Mar 09 Javascript
关于JS中的作用域中的问题思考分享
Apr 06 Javascript
为什么JavaScript没有块级作用域
May 22 #Javascript
全面解析Bootstrap中nav、collapse的使用方法
May 22 #Javascript
全面解析bootstrap格子布局
May 22 #Javascript
Bootstrap模块dropdown实现下拉框响应
May 22 #Javascript
基于Bootstrap实现图片轮播效果
May 22 #Javascript
基于Vue.js的表格分页组件
May 22 #Javascript
js正则表达式replace替换变量方法
May 21 #Javascript
You might like
PHP图片上传类带图片显示
2006/11/25 PHP
IP攻击升级,程序改进以对付新的攻击
2010/11/23 PHP
用PHP实现浏览器点击下载TXT文档的方法详解
2013/06/02 PHP
PHP针对中英文混合字符串长度判断及截取方法示例
2017/03/31 PHP
PHP实现RSA签名生成订单功能【支付宝示例】
2017/06/06 PHP
php设计模式之单例模式用法经典示例分析
2019/09/20 PHP
用ADODB.Stream转换
2007/01/22 Javascript
经典海量jQuery插件 大家可以收藏一下
2010/02/07 Javascript
删除Javascript Object中间的key
2014/11/18 Javascript
怎么引入(调用)一个JS文件
2016/05/26 Javascript
jQuery ajax 当async为false时解决同步操作失败的问题
2016/11/18 Javascript
让div运动起来 js实现缓动效果
2017/07/06 Javascript
vue左侧菜单,树形图递归实现代码
2018/08/24 Javascript
layui递归实现动态左侧菜单
2019/07/26 Javascript
Vue与React的区别和优势对比
2020/12/18 Vue.js
node.js通过Sequelize 连接MySQL的方法
2020/12/28 Javascript
深入浅析python中的多进程、多线程、协程
2016/06/22 Python
TF-IDF与余弦相似性的应用(一) 自动提取关键词
2017/12/21 Python
python模拟事件触发机制详解
2018/01/19 Python
python-docx修改已存在的Word文档的表格的字体格式方法
2018/05/08 Python
python利用微信公众号实现报警功能
2018/06/10 Python
Python 运行.py文件和交互式运行代码的区别详解
2019/07/02 Python
Python使用matplotlib实现交换式图形显示功能示例
2019/09/06 Python
Python 自由定制表格的实现示例
2020/03/20 Python
css3 伪类选择器快速复习小结
2019/09/10 HTML / CSS
下述程序的作用是计算机数组中的最大元素值及其下标
2012/11/26 面试题
Prototype如何为一个Ajax添加一个参数
2015/12/06 面试题
小学教师节活动方案
2014/01/31 职场文书
小学中秋节活动方案
2014/02/06 职场文书
美容院经理岗位职责
2014/04/03 职场文书
我的祖国演讲稿
2014/05/04 职场文书
思想作风建设心得体会
2014/10/22 职场文书
文艺节目主持词
2015/07/06 职场文书
如何用PHP实现多线程编程
2021/05/26 PHP
pytorch 权重weight 与 梯度grad 可视化操作
2021/06/05 Python
nginx之queue的具体使用
2022/06/28 Servers