理解Javascript(NodeJS)中的回调函数

1、回调函数的概念

A callback is a function that is passed as an argument to another function and is executed after its parent function has completed
回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。这个过程就叫做回调。

示例:

//定义主函数,参数是一个回调函数
function A(callback) {
    callback();  
    console.log('我是主函数1<br/>');   
    console.log('我是主函数2<br/>');
    console.log('我是主函数3<br/>');   
}

//定义回调函数
function B(){
    setTimeout("console.log('我是回调函数')", 3000);//延时3秒,模仿耗时操作  
}

//调用主函数,将函数B传进去
A(B);

输出:

我是主函数1
我是主函数1
我是主函数1
我是回调函数

定义主函数的时候,我们让代码先去执行callback()回调函数,但输出结果却是后输出回调函数的内容。
这就说明了主函数不用等待回调函数执行完,可以接着执行自己的代码 ( 异步,非阻塞 )。所以一般回调函数都用在耗时操作上面,比如ajax请求,文件处理等。

2、异步的概念

假定有一个需求: 全局变量a初值为0,然后过3秒后,让它为6,然后再打印出来,首先想到的写法如下:

var a = 0;
 
function B(x) {
    console.log(x);
}
 
function A(time) {
    setTimeout(function () {
        a=6;
    }, time);
}
 
//调用:
console.log(a);
A(3000);
B(a);

看上去,上面的代码没有问题,理论上符合我们的逻辑需求,但却发现结果是这样:

0
0

咋回事?
因为JS是一种异步执行语言,尽管timer函数内让a=6了,但是JS不会死等时间结束再跳出函数,
而是马上就会执行下一步语句(即调用B函数),但这时候3秒钟根本就没结束,a还没有被重新赋值,
所以打印出来还是为0。

用回调函数可以解决这个问题:

var a = 0;
 
function B(x) {
    console.log(x);
}
 
function A(time, callback) {
    setTimeout(function () {
        a = 6;
        callback(a);
    }, time);
}
 
//调用:
console.log(a);
A(3000, B);

这次,在A函数中添加了一个关键字callback,这不是一个普通的参数,而是一个函数参数。
一般而言,函数的形参是指由外往内向函数体传递变量的入口
但此处加了callback后则完全相反,
它是指函数体在完成某种使命后调用外部函数的出口!

这时候应该明白什么叫“回调”了吧,也就是回头调用外部函数的意思。

在本例中,当3秒钟到了后,首先a=6,然后通过关键字callback(a)调用了函数B(x),结果显示:

0
6

这个逻辑,符合我们的需求。

在写法上,也可以不需要定义函数B, 直接在调用A的时候写成function形式,
把调用部分改成这样也可以,效果完全一样:

console.log(a);
A(3000, function (x) {
    console.log(x);
});

这种写法函数名都不需要了(术语称为“匿名函数”),在nodejs代码中更为常见也更好理解,翻译成自然语言就是:定时3秒,完成后再回头调用function(x)里面的内容。

nodejs编程中大量使用了异步编程技术,这是为了高效使用硬件,同时也可以不造成同步阻塞。
其实nodejs在底层还是通过多线程技术实现的异步操作,但普通用户并不需要深究它的实现方法,我们只要做好异步处理即可。

参考:https://blog.csdn.net/rockage/article/details/79513450

================================================================

实例理解回调函数

例如有两件事情需要完成:

1、扫地

2、烧开水

按 单进程、同步 、阻塞的方式进行:

1、第一步:先打扫卫生

2、第二步:卫生打扫完毕,接着烧开水

按 单进程、异步 、非阻塞的方式进行则按顺序进行:

1、第一步:开始打扫卫生

2、第二步:到烧开水的时间,使用有鸣叫功能(回调函数)的开水壶烧开水

3、第三步:不用守着烧开水,接着打扫卫生非阻塞)

4、第四步:听到开水烧开的声音(调用回调函数),去处理开水

5、第五步:开水处理完毕,接着扫地

 


Comments are closed.