回调函数
以下是引用:
函数可以理解为一个功能体,执行它可以完成一个任务。
回调函数本质上就是一个函数,只是执行时间和执行主体与普通的函数稍有区别。
-----举个例子的分割线------------
你去食堂打饭,你喜欢吃小炒热饭菜,所以你去了一个小炒窗口。
你跟老板说了要×××盖饭,老板说:你是100号,喊到你的号你就来拿菜。
然后你在旁边跟同学吹牛、或者看手机、或者干点你想干的任何事情。。。
然后你听到老板喊100号并且把菜放到窗口,你走到窗口,拿到你的菜。
这里面就有典型的异步操作、回调函数的概念。
-----下面很烦的分割线------------
好吧,先搞清楚一些问题再回头分析
回调函数在什么场景有用?
我要在特定时候执行一个任务,至于是什么时候我自己都不知道。比如某一时间到了或者某一事件发生或者某一中断触发。
回调函数怎么起作用?
把我要执行的这个任务写成一个函数,将这个函数和某一时间或者事件或者中断建立关联。当这个关联完成的时候,这个函数华丽的从普通函数变身成为回调函数。
回调函数什么时候执行?
当该回调函数关心的那个时间或者事件或者中断触发的时候,回调函数将被执行。
一般是触发这个时间、事件或中断的程序主体(通常是个函数或者对象)观察到有一个关注这个东东的回调函数的时候,这个主体负责调用这个回调函数。
回调函数有什么好处?
最大的好处是你的程序变成异步了。也就是你不必再调用这个函数的时候一直等待这个时间的到达、事件的发生或中断的发生(万一一直不发生,你的程序会怎么样?)。再此期间你可以做做别的事情,或者四处逛逛。当回调函数被执行时,你的程序重新得到执行的机会,此时你可以继续做必要的事情了。
回调函数有什么问题吗?
既然有人问,当然就会有点问题。一个是学习成本会比普通函数高,需要有一定的抽象思维能力,需要对应用场景的理解。另一个是回调函数很多情况下会附带有跨线程操作甚至于跨进程的操作,这些都是异步带来的成本。
-----回调分析的分割线------------
你去食堂打饭,你喜欢吃小炒热饭菜,所以你去了一个小炒窗口。
你跟老板说了要×××盖饭,老板说:你是100号,喊到你的号你就来拿菜。
然后你在旁边跟同学吹牛、或者看手机、或者干点你想干的任何事情。。。
然后你听到老板喊100号并且把菜放到窗口,你走到窗口,拿到你的菜。
这里面有几个函数:
老板的部分:
1、老板提供一个点餐的函数 boss.Order(string 菜名,double 钱)
2、老板有个做饭的函数,此函数耗时较长boss.Cook()
3、老板提供一个事件,当boss.cook()执行完时,该事件被触发,boss.OnCookFinish;
你的部分:
1、你需要有一个函数去订餐,也就是你的函数中需要执行类似于boss.Order("红烧肉盖浇饭",20),比如是me.Hungry()
2、你需要有一个函数作为回调函数去关注boss.OnCookFinish事件,这样当老板做好饭,你就可以知道是不是你的好了。
由于老板的事件发生的时候中会喊编号并且吧菜放到窗口,所以你的回调函数需要能够接受1个编号和1个菜作为参数。
比如me.AcceptFood(int currNumber,object food)
所以整个程序的流程其实是这样的。
me.Hungry(){
boss.Order("红烧肉盖浇饭",20);
boss.OnCookFinish =me.AcceptFood;//此处表面,AcceptFood这个回调函数关心OnCookFinish事件,并且变成这个事件的回调函数
//此时这个函数执行完,不再等待
}
boss.Order("红烧肉盖浇饭",20){
//收钱
//配菜 前2个耗时较短
boss.Cook();//此处一般会开新线程执行cook动作
}
boss.Cook(){
//cooking~~~~~~~~~~
//完成了,下面将要触发事件,系统将检查这个事件是否有回调函数关心,有的话逐个回调。
OnCookFinish(100号,红烧肉盖浇饭);
}
至此案例基本完成了一个完整的任务流程。
======最终总结的分割线==========
回调函数在异步处理过程中的一个必要手段。目的是让me不需要等boss的长时间操作,可以在这段时间做点别的事情。