回调函数 订阅
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。回调方法 是 任何一个 被 以该回调方法为其第一个参数 的 其它方法 调用 的方法。很多时候,回调是一个当某些事件发生时被调用的方法。 展开全文
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。回调方法 是 任何一个 被 以该回调方法为其第一个参数 的 其它方法 调用 的方法。很多时候,回调是一个当某些事件发生时被调用的方法。
信息
意    思
通过函数指针调用的函数
作    用
对特定的事件或条件进行响应
中文名
回调函数
外文名
Callback Functions
回调函数机制
⑴定义一个回调函数;⑵提供函数实现的一方在初始化的时候,将回调函数的函数指针注册给调用者;⑶当特定的事件或条件发生的时候,调用者使用函数指针调用回调函数对事件进行处理。
收起全文
精华内容
参与话题
问答
  • 回调函数

    千次阅读 2019-08-31 13:14:26
    1、回调函数:是指通过函数指针调用的函数。它是定义给别人调用的函数,自己不使用。 2、注册回调函数:使用回调函数的一方。它定义一个接受函数指针的接口来接受回调函数的地址,在需要的时候调用回调函数。 3、...

    1、回调函数:是指通过函数指针调用的函数。它是定义给别人调用的函数,自己不使用。

    2、注册回调函数:使用回调函数的一方。它定义一个接受函数指针的接口来接受回调函数的地址,在需要的时候调用回调函数。

    3、定义回调函数的步骤:

    (1)确定好回调函数的形参格式。

    (2)确定谁写回调函数,谁写注册回调函数。

    (3)实现回调函数。

    (4)回调函数可用来获取状态信息(取值),也可以用来下发信息(传值)。

    4、简单的使用:

    #include <iostream>
    
    using namespace std;
    //注册回调函数(调用回调函数的函数)
    class CGisterCallBack
    {
    public:	//构造与析构
    	CGisterCallBack() {
    		m_pFunc = NULL;
    	};
    	~CGisterCallBack() {
    		if (NULL != m_pFunc)
    			m_pFunc = NULL;	//函数指针不能删除
    	}
    
    public:	//函数
    	typedef void(*pFunc)(int ID, double time);	//回调函数的格式
    	void registerFun(pFunc pF) { m_pFunc = pF; }//注册回调函数
    	void RunCallBack() { m_pFunc(1, 30.0);}		//执行别的模块注册过来的回调函数
    
    public:	//变量
    	pFunc m_pFunc;	//函数指针
    };
    
    //回调函数
    void callBack(int ID, double time)
    {
    	cout << "在" << time <<"s," << ID << "调用回调函数"  << endl;
    }
    
    //主函数
    int main()
    {
    	CGisterCallBack mCGisterCallBack;
    	mCGisterCallBack.registerFun(callBack);
    	mCGisterCallBack.RunCallBack();
    	system("pause");
    }

    输出:在30s,1调用回调函数

    展开全文
  • 回调函数

    千次阅读 2006-12-04 18:02:00
    一,回调函数我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理、用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函数)...
     一,回调函数
    

    我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理、用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢,怎么定义呢?它和其它函数(比如钩子函数)有何不同呢?

    使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。

    而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。至于如何定义回调函数,跟具体使用的API函数有关,一般在帮助中有说明回调函数的参数和返回值等。C++中一般要求在回调函数前加CALLBACK(相当于FAR PASCAL),这主要是说明该函数的调用方式。

    至于钩子函数,只是回调函数的一个特例。习惯上把与SetWindowsHookEx函数一起使用的回调函数称为钩子函数。也有人把利用VirtualQueryEx安装的函数称为钩子函数,不过这种叫法不太流行。

    也可以这样,更容易理解:回调函数就好像是一个中断处理函数,系统在符合你设定的条件时自动调用。为此,你需要做三件事:

    1.声明;

    2.定义;

    3.设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于系统调用。

    声明和定义时应注意:回调函数由系统调用,所以可以认为它属于WINDOWS系统,不要把它当作你的某个类的成员函数。


    二,回调函数、消息和事件例程


    调用(calling)机制从汇编时代起已经大量使用:准备一段现成的代码,调用者可以随时跳转至此段代码的起始地址,执行完后再返回跳转时的后续地址。CPU为此准备了现成的调用指令,调用时可以压栈保护现场,调用结束后从堆栈中弹出现场地址,以便自动返回。借堆栈保护现场真是一项绝妙的发明,它使调用者和被调者可以互不相识,于是才有了后来的函数和构件。

    此调用机制并非完美。回调函数就是一例。函数之类本是为调用者准备的美餐,其烹制者应对食客了如指掌,但实情并非如此。例如,写一个快速排序函数供他人调用,其中必包含比较大小。麻烦来了:此时并不知要比较的是何类数据--整数、浮点数、字符串?于是只好为每类数据制作一个不同的排序函数。更通行的办法是在函数参数中列一个回调函数地址,并通知调用者:君需自己准备一个比较函数,其中包含两个指针类参数,函数要比较此二指针所指数据之大小,并由函数返回值说明比较结果。排序函数借此调用者提供的函数来比较大小,借指针传递参数,可以全然不管所比较的数据类型。被调用者回头调用调用者的函数(够咬嘴的),故称其为回调(callback)。

    回调函数使程序结构乱了许多。Windows API 函数集中有不少回调函数,尽管有详尽说明,仍使初学者一头雾水。恐怕这也是无奈之举。

    无论何种事物,能以树形结构单向描述毕竟让人舒服些。如果某家族中孙辈又是某祖辈的祖辈,恐怕无人能理清其中的头绪。但数据处理之复杂往往需要构成网状结构,非简单的客户/服务器关系能穷尽。

    Windows 系统还包含着另一种更为广泛的回调机制,即消息机制。消息本是 Windows 的基本控制手段,乍看与函数调用无关,其实是一种变相的函数调用。发送消息的目的是通知收方运行一段预先准备好的代码,相当于调用一个函数。消息所附带的 WParam 和 LParam 相当于函数的参数,只不过比普通参数更通用一些。应用程序可以主动发送消息,更多情况下是坐等 Windows 发送消息。一旦消息进入所属消息队列,便检感兴趣的那些,跳转去执行相应的消息处理代码。操作系统本是为应用程序服务,由应用程序来调用。而应用程序一旦启动,却要反过来等待操作系统的调用。这分明也是一种回调,或者说是一种广义回调。其实,应用程序之间也可以形成这种回调。假如进程 B 收到进程 A 发来的消息,启动了一段代码,其中又向进程 A 发送消息,这就形成了回调。这种回调比较隐蔽,弄不好会搞成递归调用,若缺少终止条件,将会循环不已,直至把程序搞垮。若是故意编写成此递归调用,并设好终止条件,倒是很有意思。但这种程序结构太隐蔽,除非十分必要,还是不用为好。

    利用消息也可以构成狭义回调。上面所举排序函数一例,可以把回调函数地址换成窗口 handle。如此,当需要比较数据大小时,不是去调用回调函数,而是借 API 函数 SendMessage 向指定窗口发送消息。收到消息方负责比较数据大小,把比较结果通过消息本身的返回值传给消息发送方。所实现的功能与回调函数并无不同。当然,此例中改为消息纯属画蛇添脚,反倒把程序搞得很慢。但其他情况下并非总是如此,特别是需要异步调用时,发送消息是一种不错的选择。假如回调函数中包含文件处理之类的低速处理,调用方等不得,需要把同步调用改为异步调用,去启动一个单独的线程,然后马上执行后续代码,其余的事让线程慢慢去做。一个替代办法是借 API 函数 PostMessage 发送一个异步消息,然后立即执行后续代码。这要比自己搞个线程省事许多,而且更安全。

    如今我们是活在一个 object 时代。只要与编程有关,无论何事都离不开 object。但 object 并未消除回调,反而把它发扬光大,弄得到处都是,只不过大都以事件(event)的身份出现,镶嵌在某个结构之中,显得更正统,更容易被人接受。应用程序要使用某个构件,总要先弄清构件的属性、方法和事件,然后给构件属性赋值,在适当的时候调用适当的构件方法,还要给事件编写处理例程,以备构件代码来调用。何谓事件?它不过是一个指向事件例程的地址,与回调函数地址没什么区别。

    不过,此种回调方式比传统回调函数要高明许多。首先,它把让人不太舒服的回调函数变成一种自然而然的处理例程,使编程者顿觉气顺。再者,地址是一个危险的东西,用好了可使程序加速,用不好处处是陷阱,程序随时都会崩溃。现代编程方式总是想法把地址隐藏起来(隐藏比较彻底的如 VB 和 Java),其代价是降低了程序效率。事件例程(?)使编程者无需直接操作地址,但并不会使程序减速。
    (例程似乎是进程的台湾翻译。)


    三,精妙比喻:回调函数还真有点像您随身带的BP机:告诉别人号码,在它有事情时Call您。

    回调用于层间协作,上层将本层函数安装在下层,这个函数就是回调,而下层在一定条件下触发回调,例如作为一个驱动,是一个底层,他在收到一个数据时,除了完成本层的处理工作外,还将进行回调,将这个数据交给上层应用层来做进一步处理,这在分层的数据通信中很普遍。其实回调和API非常接近,他们的共性都是跨层调用的函数。但区别是API是低层提供给高层的调用,一般这个函数对高层都是已知的;而回调正好相反,他是高层提供给底层的调用,对于低层他是未知的,必须由高层进行安装,这个安装函数其实就是一个低层提供的API,安装后低层不知道这个回调的名字,但它通过一个函数指针来保存这个回调,在需要调用时,只需引用这个函数指针和相关的参数指针。??? 其实:回调就是该函数写在高层,低层通过一个函数指针保存这个函数,在某个事件的触发下,低层通过该函数指针调用高层那个函数。



    软件模块之间总是存在着一定的接口,从调用方式上,可以把他们分为三类:同步调用、回调和异步调用。同步调用是一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用;回调是一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口;异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。回调和异步调用的关系非常紧密,通常我们使用回调来实现异步消息的注册,通过异步调用来实现消息的通知。同步调用是三者当中最简单的,而回调又常常是异步调用的基础。
     
    对于不同类型的语言(如结构化语言和对象语言)、平台(Win32、JDK)或构架(CORBA、DCOM、WebService),客户和服务的交互除了同步方式以外,都需要具备一定的异步通知机制,让服务方(或接口提供方)在某些情况下能够主动通知客户,而回调是实现异步的一个最简捷的途径。

    对于一般的结构化语言,可以通过回调函数来实现回调。回调函数也是一个函数或过程,不过它是一个由调用方自己实现,供被调用方使用的特殊函数。

    在面向对象的语言中,回调则是通过接口或抽象类来实现的,我们把实现这种接口的类成为回调类,回调类的对象成为回调对象。对于象C++或Object Pascal这些兼容了过程特性的对象语言,不仅提供了回调对象、回调方法等特性,也能兼容过程语言的回调函数机制。

    Windows平台的消息机制也可以看作是回调的一种应用,我们通过系统提供的接口注册消息处理函数(即回调函数),从而实现接收、处理消息的目的。由于Windows平台的API是用C语言来构建的,我们可以认为它也是回调函数的一个特例。

    对于分布式组件代理体系CORBA,异步处理有多种方式,如回调、事件服务、通知服务等。事件服务和通知服务是CORBA用来处理异步消息的标准服务,他们主要负责消息的处理、派发、维护等工作。对一些简单的异步处理过程,我们可以通过回调机制来实现。

    下面我们集中比较具有代表性的语言(C、Object Pascal)和架构(CORBA)来分析回调的实现方式、具体作用等。

    2 过程语言中的回调(C)


    2.1 函数指针
    回调在C语言中是通过函数指针来实现的,通过将回调函数的地址传给被调函数从而实现回调。因此,要实现回调,必须首先定义函数指针,请看下面的例子:

    void Func(char *s);// 函数原型
    void (*pFunc) (char *);//函数指针

    可以看出,函数的定义和函数指针的定义非常类似。

    一般的化,为了简化函数指针类型的变量定义,提高程序的可读性,我们需要把函数指针类型自定义一下。
    typedef void(*pcb)(char *);

    回调函数可以象普通函数一样被程序调用,但是只有它被当作参数传递给被调函数时才能称作回调函数。

    被调函数的例子:

    void GetCallBack(pcb callback)
    {
     /*do something*/
    }
    用户在调用上面的函数时,需要自己实现一个pcb类型的回调函数:
    void fCallback(char *s)
    {
    /* do something */
    }
    然后,就可以直接把fCallback当作一个变量传递给GetCallBack,
    GetCallBack(fCallback);

    如果赋了不同的值给该参数,那么调用者将调用不同地址的函数。赋值可以发生在运行时,这样使你能实现动态绑定。

    2.2 参数传递规则
    到目前为止,我们只讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。许多编译器有几种调用规范。如在Visual C++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)。C++ Builder也支持_fastcall调用规范。调用规范影响编译器产生的给定函数名,参数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或者被调用者)以及参数传递机制(堆栈,CPU寄存器等)。

    将调用规范看成是函数类型的一部分是很重要的;不能用不兼容的调用规范将地址赋值给函数指针。例如:

    // 被调用函数是以int为参数,以int为返回值
     __stdcall int callee(int);

    // 调用函数以函数指针为参数
     void caller( __cdecl int(*ptr)(int));

    // 在p中企图存储被调用函数地址的非法操作
    __cdecl int(*p)(int) = callee; // 出错

     指针p和callee()的类型不兼容,因为它们有不同的调用规范。因此不能将被调用者的地址赋值给指针p,尽管两者有相同的返回值和参数列

    2.3 应用举例
    C语言的标准库函数中很多地方就采用了回调函数来让用户定制处理过程。如常用的快速排序函数、二分搜索函数等。

    快速排序函数原型:

    void qsort(void *base, size_t nelem, size_t width, int (_USERENTRY *fcmp)(const void *, const void *));
    二分搜索函数原型:
    void *bsearch(const void *key, const void *base, size_t nelem,
    size_t width, int (_USERENTRY *fcmp)(const void *, const void *));

    其中fcmp就是一个回调函数的变量。

    下面给出一个具体的例子:

    #i nclude
    #i nclude

    int sort_function( const void *a, const void *b);
    int list[5] = { 54, 21, 11, 67, 22 };

    int main(void)
    {
    int x;

    qsort((void *)list, 5, sizeof(list[0]), sort_function);
    for (x = 0; x < 5; x++)
    printf("%in", list[x]);
    return 0;
    }

    int sort_function( const void *a, const void *b)
    {
    return *(int*)a-*(int*)b;
    }

    2.4 面向对象语言中的回调(Delphi)

    Dephi与C++一样,为了保持与过程语言Pascal的兼容性,它在引入面向对象机制的同时,保留了以前的结构化特性。因此,对回调的实现,也有两种截然不同的模式,一种是结构化的函数回调模式,一种是面向对象的接口模式。

    展开全文
  • 在C++编程,尤其时写Qt程序时,需要大量使用回调函数,在网上也有很多大牛对回调函数的使用进行了讲解,但是很多都是针对某一个或者两个特定的类型的。我在这篇文章中对网上关于回调函数的使用进行了归纳总结,并且...

    引言:

    在C++编程,尤其时写Qt程序时,需要大量使用回调函数,在网上也有很多大牛对回调函数的使用进行了讲解,但是很多都是针对某一个或者两个特定的类型的。我在这篇文章中对网上关于回调函数的使用进行了归纳总结,并且对每一种类型的回调函数都写了一个简单的例子来实现,每个例子都可以在vs2015中编译通过。其中需要用到 bind和function的代码,由于使用了C++11的新标准,所以在vc6.0中可能没法直接编译通过。

    一、普通函数作为回调函数

    普通函数作为回调函数时,使用普通的函数指针进行传入。

    例:

    #include <iostream>
    using namespace std;
    typedef int (*pGeneralFun)(int, int);                // 定义函数指针
    int sum(int a, int b){
        return a+b;
    } 
    void result(pGeneralFun fun, int a, int b){      // 定义接口韩式,在接口函数内实现回调函数的调用
        cout<<(*fun)(a, b)<<endl;
    }
    void main(){
        result(sum, 1, 2);                // 普通函数的函数名即为指针
    }

     

    二、类的成员函数作为回调函数

    1、类的静态成员函数作为回调函数

    a、在类外定义接口函数

    #include <iostream>
    using namespace std;
    typedef int(*pGeneralFun)(int, int);              // 类的静态成员函数的函数指针与普通函数一致
    class Test{
    public:
        static int Max(int a, int b){
            return a>=b? a:b;
        }
    };
    void result(pGeneralFun fun, int a, int b){    // 类的静态成员函数的接口函数定义与普通函数一样
        cout<<(*fun)(a, b)<<endl;
    }
    void main(){
        result(Test::Max, 3, 4);           // 类的静态成员函数,类名::函数名 表示函数的地址
    }

     

    b、在类内定义接口函数

    #include <iostream>
    using namespace std;
    typedef int(*pGeneralFun)(int, int);              // 类的静态成员函数的函数指针与普通函数一致
    class Test{
    public:
        static int Max(int a, int b){
            return a>=b? a:b;
        }
        void result(pGeneralFun fun, int a, int b){    // 在类内部定义接口函数,定义形式与类外一样
            cout<<(*fun)(a, b)<<endl;
        }
    };
    void main(){
        Test test;
        test.result(Test::Max, 5, 6);           // 调用在类内定义的接口函数
    }

     

    c、在类A中定义回调函数,在类B中定义接口函数

    #include <iostream>
    using namespace std;
    typedef int (*pGeneralFun)(int, int);
    class A{
    public:
        static int Max(int a, int b){             // 在类 A 中定义回调函数
            return a>=b?a:b;
        }
    };
    class B{
    public:
        void result(pGeneralFun fun, int a, int b){
            cout<<(*fun)(a, b)<<endl;
        }
    };
    void main(){
        B b;
        A a;
        b.result(A::Max, 4, 5);
    }

     

    小结:

    当类内的成员函数为静态成员函数时,将该函数作为回调函数,使用的方式与普通函数基本上没有区别。只是当接口函数定义在类的内部时,调用接口函数要使用对象名。

    2、类的非静态成员函数作为回调函数

    a、在类外定义接口函数

    #include <iostream>
    using namespace std;
    class Test;                             // 在定义函数指针之前必须先声明类
    typedef int (Test::*pClassFun)(int, int);                         // 定义函数指针
    class Test{
    public:
        int sum(int a, int b){
        return a+b;
        }
    };
    void result(Test *test, pClassFun fun, int a, int b){       // 在定义接口函数时要传入一个对象
        cout<<(test->*fun)(a, b)<<endl;
    }
    void main(){
        Test test;
        result(&test, &Test::sum, 3, 4);               // 对于非静态成员,要使用&来创建指向成员的指针
    }

     

    b、在类内定义接口函数

    #include <iostream>
    using namespace std;
    class Test;
    typedef int(Test::*pClassFun)(int, int);
    class Test{
    public:
        int sum(int a, int b){
            return a+b;
        }
        void result(pClassFun fun, int a, int b){
            cout<<(this->*fun)(a, b)<<endl;               // 必须要用隐含的 this 指针来指向传入的函数
        }
    };
    void main(){
        Test test;
        test.result(&Test::sum, 3, 4);
    }

     

    c、在类 A 内定义回调函数,在类 B 内定义接口函数

    方式一:

    #include <iostream>
    using namespace std;
    class A;                  // 必须先声明类 A
    typedef int(A::*pClassFun)(int, int);
    class A{
    public:
        int sum(int a, int b){
            return a+b;
        }
    };
    class B{
    public:
        void result(A *test, pClassFun fun, int a, int b){
            cout<<(test->*fun)(a, b)<<endl;
        }
    };
    void main(){
        A a;
        B b;
        b.result(&a, &A::sum, 2, 3);
    }

     

    方式二:

    使用 stl 中的 function 和 bind

    #include <iostream>
    #include <functional>    // bind 的声明位于 头文件 functional 中
    using namespace std;
    using namespace std::placeholder;      // 占位符的定义位于命名空间 placeholder 中
    
    typedef function<int(int, int)>Fun;         // 定义的是一个函数模板,指针类型
    
    class B{
    public:
        void call(int a, Fun f) {               // 在类 B 中定义接口函数
            cout<<f(a, 2)<<endl;
        }
    };
    class A{
    public:
        int sum(int a, int b){
            return a+b;
        }
        void bind(){
            Fun fun = std::bind(&A::sum, this, _1, _2);    
            // 其中_1,_2为占位符,通过bind函数将this指针隐式结合在子函数的参数中
            // 这一步只能在类 A 中实现,因为this指针指的是由类A产生的对象
            B b;
            b.call(1, fun);               // 在类 A 中调用 B 中的接口函数
            // 调用接口函数的这一步如果要在主函数中实现,则可以使bind函数返回 fun,在主函数中
            // 使用b.call(1, a.bind())来进行调用
        }
    };
    int main(){
        A a;
        B b;
        a.bind();
        system("pause");
    }
    

    展开全文
  • 深入理解:回调函数

    万次阅读 多人点赞 2019-06-21 15:36:09
    关于回调函数到底是什么,已经困扰了我很久了~ 在知乎上看到几位大神的帖子,才恍然大悟 作者:no.body 链接:https://www.zhihu.com/question/19801131/answer/27459821 来源:知乎 作者:常溪玲 链接...

    关于回调函数到底是什么,已经困扰了我很久了~

    在知乎上看到几位大神的帖子,才恍然大悟

    作者:no.body
    链接:https://www.zhihu.com/question/19801131/answer/27459821
    来源:知乎

    作者:常溪玲
    链接:https://www.zhihu.com/question/19801131/answer/13005983
    来源:知乎

    首先要明确的一点是,函数也可以作为函数的参数来传递

    好了,有了这个概念我们来说明回调函数到底是怎么回事

    首先至少要有 3 种类型的函数

    • 主函数:相当于整个程序的引擎,调度各个函数按序执行

    • 回调函数:一个独立的功能函数,如写文件函数

    • 中间函数:一个介于主函数和回调函数之间的函数,登记回调函数,通知主函数,起到一个桥梁的作用

    接下来我们一起来看下示例代码:

    #!/usr/bin/env python3
    # -*- coding: UTF-8 -*-
    
    # 回调函数1
    def callback1(x):
        return x * 2 
    
    # 回调函数2
    def callback2(x):
        return x ** 2
    
    # 中间函数
    def middle(x, func):
        return 100 + func(x)
    
    # 主函数
    def main():
    
        x = 1 
    
        a = middle(x, callback1)
        print(a)
    
        b = middle(x, callback2)
        print(b)
    
        c = middle(x, lambda x: x + 2)
        print(c)
    
    main()
    

    运行结果:

    102
    101
    103
    

    代码看懂以后我们接下来分析一下代码的逻辑

    首先我们在主函数执行过程中需要用到一个功能 x * 2,而 callback1 函数就提供这个功能,我们就把这个函数称之为 回调函数(至于为什么要叫“回调函数”,不能叫别的呢?其实这只是人为规定的一个名字。你也可以叫“极客点儿专属函数”,但是到时候你又会问为什么要叫“极客点儿专属函数”,它特么的总的有个名字吧!所以叫“回调函数”就是王八的屁股:规定!)。

    这时候我们的 主函数 要调用它,但是有的时候在开发过程中遇到需要写硬盘的操作,这时候我们为了避免程序的阻塞,就需要用到异步 I/O。就是你自己先写着玩儿,爸爸去干别的事情去了,等你完事儿再来通知我。正是因为这种机制所以得有一个 登记回调函数通知主函数执行完成 的“地方”,这个地方就是 中间函数

    有上述内容我们就可以推导出回调函数执行的流程了:

    1. 主函数需要调用回调函数

    2. 中间函数登记回调函数

    3. 触发回调函数事件

    4. 调用回调函数

    5. 响应回调事件

    回调实际上有两种:阻塞式回调延迟式回调 也可以叫做 同步回调异步回调

    两者的区别在于:

    在阻塞式回调里,回调函数的调用一定发生在主函数返回之前

    在延迟式回调里,回调函数的调用有可能是在起始函数返回之后

    上述示例均为 同步回调,异步需要用到多进程、多线程、协程这些概念,下次有机会再说

    最后用一个例子说明一下到底说明是回调函数:

    你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。

    在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做 触发回调事件,店员给你打电话叫做 调用回调函数,你到店里去取货叫做 响应回调事件

    展开全文

空空如也

1 2 3 4 5 ... 20
收藏数 64,604
精华内容 25,841
关键字:

回调函数