JavaScript中的回调函数非常重要,几乎无处不在,下面就来看看到底什么是回调函数。
百度百科:
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
维基百科:
In computer programming, a callback is a reference to a piece of executable code that is passed as an argument to other code.
在计算机程序设计中,回调是对作为一个参数传递给其他代码的一段可执行代码的引用。
jQuery:
A callback is a function that is passed as an argument to another function and is executed after its parent function has completed. The special thing about a callback is that functions that appear after the "parent" can execute before the callback executes. Another important thing to know is how to properly pass the callback. This is where I have often forgotten the proper syntax.
回调是函数作为参数传递给另一个函数并在其父函数完成后执行的函数。回调的特殊之处在于,在“回调”执行之前,出现在“父”之后的函数可以执行。另一个重要的事情是如何正确地传递回调。这就是我经常忘记正确语法的地方。
这里的关键点就是:
- 函数作为参数传递给另一个函数
一、函数指针和调用函数
看下这段代码
function say(param) {
console.log(param)
}
我们知道,函数名只是一个指向对象的指针,所以当执行console.log(say)的时候,输出的应当是函数本身的字符串,也就是say(param) {console.log(param);},但是当执行say('hellow')的时候,就是调用函数了,控制台会输出hello。
二、回调函数
在上面代码的基础上,添加如下代码:
function execute(value, callback) {
// 最好保证回调函数存在且必须是函数引用或者函数表达式
if ((callback && typeof (callback) === 'function')) {
callback(value);
}
}
execute('Hello Seven', say); // Hello Seven
这里我们看到execute()函数有两个参数,一个是value,一个是callback,并且在函数体内执行了callback,那么callback就是一个函数参数;
执行execute()方法的时候将say()函数的指针作为参数传递给了execute(),并且在execute()内部进行了调用,也就是在函数excute()内部执行了say()方法,say()就是execute()的回调函数。
因此,在JavaScript中,回调函数的具体定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A。我们就说函数A叫做回调函数。如果没有名称(函数表达式),就叫做匿名回调函数。
稍微调整一下上例,然后再次执行:
execute('我是匿名回调函数',function(param){
alert(param);
});
function(param){alert(param)}就是一个匿名回调函数。
三、异步回调函数
上述的回调函数是一个同步(阻塞)中使用回调函数的比较简单的例子,在函数execute()函数体内,会按照js单线程的执行方式,从上往下执行代码。这种同步的机制,会阻塞execute()函数后面代码的执行,如果该函数体内需要执行的东西比较多,就会需要等待很久,这时候异步的回调函数就很有必要了。
我们最常见的异步请求,应该就是AJAX了,就模拟一下AJAX:
function $http(url, callback) {
// 创建请求
var xmlhttp;
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp = new XMLHttpRequest();
} else {
// IE6, IE5 浏览器执行代码
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
// 服务器响应
xmlhttp.onreadystatechange = function () {
// 请求完成
if (xmlhttp.readyState === 4) {
// 请求成功
if (xmlhttp.status === 200) {
// 在请求对象的上下文环境中调用回调函数
callback.call(xmlhttp.responseText);
} else {
// 请求失败,返回状态码,进行判断
console.log(xmlhttp.status);
}
}
}
// 发送请求--默认get,异步
xmlhttp.open('GET', url, true);
xmlhttp.send();
}
// 调用函数,进行异步请求,并执行一个匿名回调函数
$http('/data/test.txt', function () {
console.log(this);
});
// 执行一些其他的语句
console.log('此语句会在异步请求之前先输出');
上述代码简单封装了AJAX,然后进行了调用,在调用请求函数的时候,在请求函数的后面还执行了一些其他的语句,结果发现,其他的语句先执行了,这就是异步回调的作用,当我们不需要关心函数执行的结果的时候,可以让它在未来的某个时间去执行,可以先执行别的。
四、回调函数的使用场合
- 资源加载:动态加载js文件之后执行回调,AJAX请求,图片加载完成之后执行回调等等
- setTimeout的延迟时间设置为0,这个hack经常被用到,setTimeout调用的函数其实就是个callback的体现
五、回调函数的传参
- 将回调函数的参数作为与回调函数同等级的参数传递到主函数中
例子中的:execute('hello Seven', say); - 使用匿名回调函数,在匿名回调函数体内执行回调函数
$.get('myhtmlpage.html', function(){//带参数的使用函数表达式
myCallBack('foo', 'bar');
});











网友评论