一篇文章让你彻底理解回调函数

linux服务器开发相关视频解析:服务器为什么慢,原来这样操作,可以提升8倍
tcp专题训练营之深度解析tcp/ip协议栈
腾讯T2.3亲身经历分享,腾讯offer的获取之路
不知你是不是也有这样的疑惑,我们为什么需要回调函数这个概念呢?直接调用函数不就可以了?回调函数到底有什么作用?程序员到底该如何理解回调函数?
这篇文章就来为你解答这些问题,读完这篇文章后你的武器库将新增一件功能强大的利器 。
一切要从这样的需求说起假设你们公司要开发下一代国民App“明日油条”,一款主打解决国民早餐问题的App,为了加快开发进度,这款应用由A小组和B小组协同开发 。
其中有一个核心模块由A小组开发然后供B小组调用,这个核心模块被封装成了一个函数,这个函数就叫make_youtiao() 。
如果make_youtiao()这个函数执行的很快并可以立即返回,那么B小组的同学只需要:

  1. 调用make_youtiao()
  2. 等待该函数执行完成
  3. 该函数执行完后继续后续流程
从程序执行的角度看这个过程是这样的:
  1. 保存当前被执行函数的上下文
  2. 开始执行make_youtiao()这个函数
  3. make_youtiao()执行完后,控制转回到调用函数中

一篇文章让你彻底理解回调函数

文章插图
 
如果世界上所有的函数都像make_youtiao()这么简单,那么程序员大概率就要失业了,还好程序的世界是复杂的,这样程序员才有了存在的价值 。
现实并不容易现实中make_youtiao()这个函数需要处理的数据非常庞大,假设有10000个,那么make_youtiao(10000)不会立刻返回,而是可能需要10分钟才执行完成并返回 。
这时你该怎么办呢?想一想这个问题 。
可能有的同学会问,和刚才一样直接调用不可以吗,这样多简单 。
是的,这样做没有问题,但就像爱因斯坦说的那样“一切都应该尽可能简单,但是不能过于简单” 。
想一想直接调用会有什么问题?
显然直接调用的话,那么调用线程会被阻塞暂停,在等待10分钟后才能继续运行 。在这10分钟内该线程不会被操作系统分配CPU,也就是说该线程得不到任何推进 。
这并不是一种高效的做法 。没有一个程序员想死盯着屏幕10分钟后才能得到结果 。那么有没有一种更加高效的做法呢?
这种一直等待直到另一个任务完成的模式叫做同步 。如果你是老板的话你会什么都不干一直盯着员工写代码吗?因此一种更好的做法是程序员在代码的时候老板该干啥干啥,程序员写完后自然会通知老板,这样老板和程序员都不需要相互等待,这种模式被称为异步 。
回到我们的主题,这里一种更好的方式是调用make_youtiao()这个函数后不再等待这个函数执行完成,而是直接返回继续后续流程,这样A小组的程序就可以和make_youtiao()这个函数同时进行了,就像这样:
一篇文章让你彻底理解回调函数

文章插图
 
在这种情况下,回调(callback)就必须出场了 。
为什么我们需要回调callback有的同学可能还没有明白为什么在这种情况下需要回调,别着急,我们慢慢讲 。假设我们“明日油条”App代码第一版是这样写的:
make_youtiao(10000);sell();可以看到这是最简单的写法,意思很简单,制作好油条后卖出去 。
一篇文章让你彻底理解回调函数

文章插图
 
我们已经知道了由于make_youtiao(10000)这个函数10分钟才能返回,你不想一直死盯着屏幕10分钟等待结果,那么一种更好的方法是让make_youtiao()这个函数知道制作完油条后该干什么,即,更好的调用make_youtiao的方式是这样的:“制作10000个油条,炸好后卖出去”,因此调用make_youtiao就变出这样了:
make_youtiao(10000, sell);看到了吧,现在make_youtiao这个函数多了一个参数,除了指定制作油条的数量外还可以指定制作好后该干什么,第二个被make_youtiao这个函数调用的函数就叫回调,callback 。
现在你应该看出来了吧,虽然sell函数是你定义的,但是这个函数却是被其它模块调用执行的,就像这样:
一篇文章让你彻底理解回调函数

文章插图
 
make_youtiao这个函数是怎么实现的呢,很简单:
void make_youtiao(int num, func call_back) { // 制作油条 call_back(); //执行回调 }


推荐阅读