通俗理解“回调函数”

回调机制

模块间的调用

本部分摘自https://www.cnblogs.com/xrq730/p/6424471.html

在一个应用系统中,无论使用何种语言开发,必然存在模块之间的调用,调用的方式分为几种:

(1)同步调用

同步调用是最基本并且最简单的一种调用方式,类A的方法a()调用类B的方法b(),一直等待b()方法执行完毕,a()方法继续往下走。这种调用方式适用于方法b()执行时间不长的情况,因为b()方法执行时间一长或者直接阻塞的话,a()方法的余下代码是无法执行下去的,这样会造成整个流程的阻塞。

image

(2)异步调用

image

异步调用是为了解决同步调用可能出现阻塞,导致整个流程卡住而产生的一种调用方式。类A的方法方法a()通过新起线程的方式调用类B的方法b(),代码接着直接往下执行,这样无论方法b()执行时间多久,都不会阻塞住方法a()的执行。

但是这种方式,由于方法a()不等待方法b()的执行完成,在方法a()需要方法b()执行结果的情况下(视具体业务而定,有些业务比如启异步线程发个微信通知、刷新一个缓存这种就没必要),必须通过一定的方式对方法b()的执行结果进行监听。

在Java中,可以使用Future+Callable的方式做到这一点,具体做法可以参见我的这篇文章Java多线程21:多线程下其他组件之CyclicBarrier、Callable、Future和FutureTask。

(3)回调

image

最后是回调,回调的思想是:

类A的a()方法调用类B的b()方法 类B的b()方法执行完毕主动调用类A的callback()方法 这样一种调用方式组成了上图,也就是一种双向的调用方式。

回调实例:Tom做题

数学老师让Tom做一道题,并且Tom做题期间数学老师不用盯着Tom,而是在玩手机,等Tom把题目做完后再把答案告诉老师。

1 数学老师需要Tom的一个引用,然后才能将题目发给Tom。

2 数学老师需要提供一个方法以便Tom做完题目以后能够将答案告诉他。

3 Tom需要数学老师的一个引用,以便Tom把答案给这位老师,而不是隔壁的体育老师。

回调接口,可以理解为老师接口

    //回调指的是A调用B来做一件事,B做完以后将结果告诉给A,这期间A可以做别的事情。
    //这个接口中有一个方法,意为B做完题目后告诉A时使用的方法。
    //所以我们必须提供这个接口以便让B来回调。
    //回调接口,
    public interface CallBack {
        void tellAnswer(int res);
    }

通俗理解“回调函数”

我们先来看看回调的英文定义:

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(‘我是主函数’);
}

//定义回调函数
function B(){
setTimeout(“console.log(‘我是回调函数’)”, 3000);//模仿耗时操作
}

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

//输出结果
我是主函数
我是回调函数
复制代码
  上面的代码中,我们先定义了主函数和回调函数,然后再去调用主函数,将回调函数传进去。

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


P2

最近经常看到“回调函数”这个概念,但不是很理解。为了弄明白回调函数,提出了以下三个问题:

1.什么是回调函数

回调函数就是一个通过指针调用的函数,如果你把函数指针作为参数传给另一个函数,当这个指针被用来调用所指向的函数时,我们就说这是回调函数。

通俗理解:回调函数和普通函数没有任何区别,只是函数调用时略有区别。一般调用普通函数时,直接写函数名即可;但是在调用回调函数时,是把它作为参数传递给另一个函数。

引用网上用生活场景解释回调函数的一个例子:

比如你显示器不亮了,你不知道怎么弄,那你就问在外地干IT的大表哥,你大表哥告诉你该怎么弄,然后需要你自己来操作。你大表哥知道怎么弄,但却不能自己操作,而是由你来操作。你大表哥告诉你修机器的方法就是回调函数。

2.为什么要用回调函数

回调函数可以把调用者与被调用者分开,调用者不关心谁是被调用者,只需要知道存在一个具有特定原型和限制条件的被调用函数。

从本质上讲,回调函数都是从“你想让别人执行你的代码,而你又不能动别人的代码”这种需求下产生的。因此,只能讲自己实现的函数作为参数传递给别人的函数,这样别人的函数在特定的时候会执行自己的函数。

在面向对象的编程中,回调函数可以让模块间解耦。比如,在一个下载系统中有一个文件下载模块和一个下载文件当前进度显示模块,系统要求实时的显示文件的下载进度。但显示模块不知道也不应该知道下载模块所下载文件的下载进度(面向对象设计的封装性,模块间要解耦,模块内要内聚),文件下载进度是只有下载模块才知道的事情,此时的解决办法是,给下载模块传递一个函数指针作为回调函数驱动显示模块的显示进度。

3.如何使用回调函数
根据以上的理解,自己写了一个简单的回调函数:

 
  
 
  
 
  
简单的说,回调函数,当你调用了一个函数,但是这个函数仅仅是算法的一部分,你还需要自己定义一部分算法,该函数会自动调用你自定义的“回调函数”。

如下例子:

比如你要枚举所有的窗口。可以调用EnumWindows函数。但是,EnumWindows仅仅是将窗口枚举出来,至于如何处理则需要你来定义。

就是说,当你调用EnumWindow,要指定一个回调函数,来告诉EnumWindow,当她枚举到窗口的时候,应该怎么处理这个窗口。
 
  
 
  
https://zhidao.baidu.com/question/395318887552374965.html?fr=iks&word=�ص���ͨ�����&ie=gbk
回调函数就是你写好一个函数,让预先写好的系统来调用。你去调用系统的函数,是直调。让系统调用你的函数,就是回调。但假如满足于这种一句话结论,是不会真正明白的。

回调函数可以看成,让别人做事,传进去的额外信息。

比如,A 让 B 做事,根据粒度不同,可以理解成 A 函数调用 B 函数,或者 A 类使用 B 类,或者 A 组件使用 B 组件等等。反正就是 A 叫 B 做事。

当 B 做这件事情的时候,自身的需要的信息不够,而 A 又有。就需要 A 从外面传进来,或者 B 做着做着主动向外面申请。对于 B 来说,一种被动得到信息,一种是主动去得到信息,有人给这两种方式术语,叫信息的 push,和信息的 pull。
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值