什么是callback函数?

什么是callback函数?

开发者常常因为该死的东西的名字而被callback所困惑。

callback函数是一个函数,它是:

  • 作为parameter passing给另一个函数,
  • 在某种事件之后被调用。

一旦它的父函数完成,然后调用作为parameter passing的函数。

伪代码:

// The callback method function meaningOfLife() { log("The meaning of life is: 42"); } // A method which accepts a callback method as an argument // takes a function reference to be executed when printANumber completes function printANumber(int number, function callbackFunction) { print("The number you provided is: " + number); } // Driver method function event() { printANumber(6, meaningOfLife); } 

如果你调用event(),结果如下:

 The number you provided is: 6 The meaning of life is: 42 

由于使用指针语言,callback是所谓的。 如果您不使用其中的一种,请不要使用“callback”这个名字。 只要理解这只是一个名字来描述一个方法作为参数提供给另一个方法,这样当父方法被调用时(不pipe是什么条件,如button点击,计时器滴答等),它的方法体完成后,然后调用callback方法,换句话说就是在另一个函数的“后面”调用。

不透明的定义

callback函数是您提供给另一段代码的函数,允许它被该代码调用。

有争议的例子

你为什么想做这个? 假设有一个服务需要调用。 如果服务立即返回,您只需:

  1. 叫它
  2. 等待结果
  3. 一旦结果出来,继续

例如,假设服务是factorial函数。 当你想要5!的价值5! ,你会调用factorial(5) ,并且会发生以下步骤:

  1. 您当前的执行位置已保存(在堆栈中,但这不重要)

  2. 执行交给factorial

  3. factorial完成时,它会将结果放在某个可以到达的地方

  4. 执行回到原来的位置[1]

现在假设factorial花费了很长时间,因为你给它的数量很大,它需要在某个超级计算集群上运行。 假设您预计需要5分钟才能返回结果。 你可以:

  1. 保持你的devise,晚上睡觉的时候运行你的程序,这样你就不会在一半的时间盯着屏幕

  2. devise你的程序做其他事情,而factorial正在做它的事情

如果你select第二个选项,那么callback可能适合你。

端到端的devise

为了利用callback模式,你想要的是能够以如下方式调用factorial

 factorial(really_big_number, what_to_do_with_the_result) 

第二个参数what_to_do_with_the_result是你发送给factorial的函数,希望factorial在返回之前会调用它的结果。

是的,这意味着需要编写支持callback的factorial

现在假设你希望能够传递一个参数给你的callback函数。 现在你不能,因为你不会去调用它, factorial是。 因此,需要编写factorial以允许您传递参数,并在调用它时将它们交给您的callback函数。 它可能看起来像这样:

 factorial (number, callback, params) { result = number! // i can make up operators in my pseudocode callback (result, params) } 

现在, factorial允许这种模式,你的callback可能看起来像这样:

 logIt (number, logger) { logger.log(number) } 

你的要求是factorial

 factorial(42, logIt, logger) 

如果你想从logIt返回一些东西呢? 那么,你不能,因为factorial没有注意到它。

那么,为什么不能factorial回报你的callback回报?

使其非阻塞

由于执行是为了在阶段完成时移交给callback,所以它不应该返回任何东西给调用者。 理想情况下,它会以某种方式在另一个线程/进程/机器上启动它的工作,并立即返回,以便继续,也许是这样的:

 factorial(param_1, param_2, ...) { new factorial_worker_task(param_1, param_2, ...); return; } 

这现在是一个“asynchronous调用”,这意味着当你调用它时,它立即返回,但还没有真正完成它的工作。 所以你确实需要一些机制来检查它,并在结束时得到它的结果,并且你的程序在这个过程中变得更加复杂。

顺便说一下,使用这种模式factorial_worker_task可以asynchronous启动您的callback,并立即返回。

所以你会怎么做?

答案是保持在callback模式。 每当你想写

 a = f() g(a) 

f是asynchronous调用的,你会写

 f(g) 

其中g作为callback传递。

这从根本上改变了你的程序的stream程拓扑 ,并且需要一些习惯。

您的编程语言可以为您提供一种即时创buildfunction的方法。 在上面的代码中,函数g可能小于print (2*a+1) 。 如果你的语言要求你把它定义为一个单独的函数,并且完全不必要的名字和签名,那么如果你使用这个模式的话,你的生活将会变得不愉快。

另一方面,如果你的语言允许你创buildlambdaexpression式,那么你的状态就会好得多。 最后你会写出类似的东西

 f( func(a) { print(2*a+1); }) 

这是非常好的。

如何通过callback

你将如何将callback函数传递给factorial ? 那么,你可以通过多种方式做到这一点。

  1. 如果被调用的函数在同一个进程中运行,则可以传递一个函数指针

  2. 或者,也许你想在你的程序中维护一个fn name --> fn ptr的字典,在这种情况下你可以通过这个名字

  3. 也许你的语言允许你定义函数就地,可能作为lambda! 它在内部创build某种对象并传递一个指针,但是您不必担心这一点。

  4. 也许你所调用的函数是在一个完全独立的机器上运行的,而且你正在使用像HTTP这样的networking协议来调用它。 您可以将您的callback公开为HTTP可调用函数,并传递其URL。

你明白了。

callback近期兴起

在这个networking时代,我们已经进入了,我们所调用的服务往往是通过networking。 我们经常无法控制这些服务,即我们没有写这些服务,我们没有维护这些服务,我们无法确保这些服务已经启动,或者如何执行。

但是我们不能指望我们的程序在我们等待这些服务响应的时候阻止。 意识到这一点,服务提供商通常使用callback模式来deviseAPI。

JavaScript支持很好的callback,例如lambdas和闭包。 JavaScript世界中有很多活动,无论是在浏览器上还是在服务器上。 甚至还有针对移动开发的JavaScript平台。

随着我们的前进,越来越多的人将编写asynchronous代码,对此,这种理解将是必不可less的。

请注意,callback是一个字。

维基百科callback页面解释得非常好。

从维基百科页面引用:

在计算机编程中,callback是对可执行代码或可执行代码的引用,作为parameter passing给其他代码。 这允许较低级别的软件层调用在较高级别层中定义的子程序(或function)。

一个外行人的回应是,这是一个函数,不是由你调用,而是由用户或浏览器在某个事件发生之后或者在一些代码被处理之后调用的。

我相信这个“​​callback”的术语在很多地方被误用了。 我的定义是这样的:

callback函数是您传递给某个人的函数,让他们在某个时间点调用它。

我想人们只是读了维基定义的第一句话:

callback是对可执行代码或可执行代码的引用,作为parameter passing给其他代码。

我一直在用很多的API,看到各种不好的例子。 许多人倾向于命名一个函数指针(对可执行代码的引用)或匿名函数(一段可执行代码)“callback”,如果它们只是函数,为什么还需要另外一个名字呢?

实际上只有维基定义中的第二句揭示了callback函数和正常函数之间的区别:

这允许较低级别的软件层调用在较高级别层中定义的子程序(或function)。

所以区别在于你要传递函数的方式以及函数的传递方式。 如果您只是定义一个函数并将其传递给另一个函数,并直接在该函数体中调用它,则不要将其称为callback函数。 定义说你传入的函数会被“低级”函数调用。

我希望人们可以停止在模棱两可的语境中使用这个词,它不能帮助人们更好地理解。

callback函数是在满足某个条件时应该调用的函数。 callback函数不是立即调用,而是在将来的某个时刻调用。

通常,当一个任务正在启动时,它将被asynchronous完成(也就是说,在调用函数返回之后会结束一段时间)。

例如,一个请求网页的函数可能要求其调用者提供一个callback函数,当网页完成下载时将会调用该函数。

在电话系统方面,回叫最容易描述。 函数调用类似于在电话上打电话给某个人,问她一个问题,得到一个答案,然后挂断; 添加一个callback改变了这个比喻,所以在问她一个问题之后,你还可以给她你的姓名和电话号码,这样她就可以给你回电话了。

– Paul Jakubik,“C ++中的callback实现”

让我们保持简单。 什么是回拨function?

按比喻和类比的例子

我有一个秘书。 我每天都要求她:(i)在邮局把这个公司的邮件寄出去,然后做完:(ii)我为那些便签上的任何一个任务写的。

现在,粘滞便笺上的任务是什么? 任务每天都有变化。

假设在这一天,我要求她打印一些文件。 所以我把它写在粘滞便笺上,然后把它放在桌子上,还有需要寄出的邮件。

综上所述:

  1. 首先,她需要放下邮件
  2. 完成之后,她需要打印一些文件。

回拨function是第二项任务:打印这些文件。 因为它是在邮件丢弃之后完成的,并且因为告诉她打印文档的便条与她最需要的邮件一起被提供给她。

现在让我们将这与编程词汇

  • 这种情况下的方法名称是:DropOffMail。
  • callback函数是:PrintOffDocuments。 PrintOffDocuments是callback函数,因为我们希望秘书在DropOffMail运行后才这样做。
  • 所以我会把“PrintOffDocuments”作为“参数”传递给DropOffMail方法,这是重要的一点。

就是这样。 而已。 我希望能为你解决 – 如果没有,发表评论,我会尽我所能澄清。

callback函数是您为现有的函数/方法指定的函数,当某个操作完成时需要调用,需要额外的处理等。

例如,在Javascript中,或者更具体地说jQuery,你可以指定一个在animation完成时调用的callback参数。

在PHP中, preg_replace_callback()函数允许您提供一个函数,当正则expression式匹配时,将会调用匹配的string作为参数。

Call After将是一个比愚蠢的名字更好的名字, callback 。 当或者如果条件在一个函数中得到满足时,调用另一个函数, Call After函数,作为参数接收的函数。

而不是在一个函数中对一个内部函数进行硬编码,而是写一个函数来接受一个已经写好的Call After函数作为参数。 “ Call After”可能会根据接收参数的函数中的代码检测到的状态更改进行调用。

这使得callback听起来像方法结束时的返回语句。

我不确定这是什么。

我认为callback实际上是一个函数的调用,作为另一个函数被调用和完成的结果。

我也认为callback是为了解决原始的调用,一种“你要求的东西,我已经做了 – 只是想让我知道 – 回到你身上”。

这个问题的简单答案是一个callback函数是一个通过函数指针调用的函数。 如果将函数的指针(地址)作为parameter passing给另一个函数,那么当该指针用于调用函数时,它指向的是callback函数

假设我们有一个函数sort(int *arraytobesorted,void (*algorithmchosen)(void)) ,它可以接受一个函数指针作为它的参数,它可以在sort()的某个实现中使用。 然后,这里由函数指针algorithmchosen寻址的代码被称为callback函数

而看到的好处是,我们可以select任何algorithm,如:

  1. algorithmchosen = bubblesort 2. algorithmchosen = heapsort 3. algorithmchosen = mergesort ... 

比方说,原型已经实现了:

  1. `void bubblesort(void)` 2. `void heapsort(void)` 3. `void mergesort(void)` ... 

这是一个用于实现面向对象编程中的多态性的概念

看图像:) 这是如何工作的

主程序使用callback函数名称调用库函数(也可能是系统级函数)。 这个callback函数可能以多种方式实现。 主程序根据需要select一个callback。

最后,库函数在执行期间调用callback函数。

“在计算机编程中,callback是对可执行代码或可执行代码的引用,作为parameter passing给其他代码。 这允许较低级别的软件层调用在较高级别层中定义的子程序(或function)。

使用函数指针在C中进行callback

在C中,使用函数指针来实现callback。 函数指针 – 顾名思义,是指向函数的指针。

例如,int(* ptrFunc)();

这里,ptrFunc是一个函数的指针,它不接受任何参数并返回一个整数。 不要忘记放在括号中,否则编译器会认为ptrFunc是一个正常的函数名,它不需要任何东西,并返回一个指向整数的指针。

这里是演示函数指针的一些代码。

 #include<stdio.h> int func(int, int); int main(void) { int result1,result2; /* declaring a pointer to a function which takes two int arguments and returns an integer as result */ int (*ptrFunc)(int,int); /* assigning ptrFunc to func's address */ ptrFunc=func; /* calling func() through explicit dereference */ result1 = (*ptrFunc)(10,20); /* calling func() through implicit dereference */ result2 = ptrFunc(10,20); printf("result1 = %d result2 = %d\n",result1,result2); return 0; } int func(int x, int y) { return x+y; } 

现在让我们尝试使用函数指针来理解C中的callback的概念。

完整的程序有三个文件:callback.c,reg_callback.h和reg_callback.c。

 /* callback.c */ #include<stdio.h> #include"reg_callback.h" /* callback function definition goes here */ void my_callback(void) { printf("inside my_callback\n"); } int main(void) { /* initialize function pointer to my_callback */ callback ptr_my_callback=my_callback; printf("This is a program demonstrating function callback\n"); /* register our callback function */ register_callback(ptr_my_callback); printf("back inside main program\n"); return 0; } /* reg_callback.h */ typedef void (*callback)(void); void register_callback(callback ptr_reg_callback); /* reg_callback.c */ #include<stdio.h> #include"reg_callback.h" /* registration goes here */ void register_callback(callback ptr_reg_callback) { printf("inside register_callback\n"); /* calling our callback function my_callback */ (*ptr_reg_callback)(); } 

如果我们运行这个程序,输出将是

这是一个程序,演示main_callback里面的register_callback里面的函数callback

高层函数调用低层函数作为普通调用,callback机制允许低层函数通过指向callback函数的指针调用高层函数。

使用接口在Java中callback

Java没有函数指针的概念它通过它的接口机​​制实现了callback机制在这里,我们声明一个接口有一个方法,当被调用者完成任务

让我通过一个例子来演示它:

callback接口

 public interface Callback { public void notify(Result result); } 

来电者或更高级别的人

 public Class Caller implements Callback { Callee ce = new Callee(this); //pass self to the callee //Other functionality //Call the Asynctask ce.doAsynctask(); public void notify(Result result){ //Got the result after the callee has finished the task //Can do whatever i want with the result } } 

被调用者或下层function

 public Class Callee { Callback cb; Callee(Callback cb){ this.cb = cb; } doAsynctask(){ //do the long running task //get the result cb.notify(result);//after the task is completed, notify the caller } } 

callback使用EventListener模式

  • 列表项目

这个模式用于通知0到n个观察者/监听者特定的任务已经完成

  • 列表项目

Callback机制和EventListener / Observer机制的不同之处在于,在callback中,被调用者通知单个调用者,而在Eventlisener / Observer中,被调用者可以通知任何对该事件感兴趣的人(通知可能转到其他部分没有触发任务的应用程序)

让我通过一个例子来解释它。

事件接口

 public interface Events { public void clickEvent(); public void longClickEvent(); } 

类小工具

 package com.som_itsolutions.training.java.exampleeventlistener; import java.util.ArrayList; import java.util.Iterator; public class Widget implements Events{ ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>(); ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>(); @Override public void clickEvent() { // TODO Auto-generated method stub Iterator<OnClickEventListener> it = mClickEventListener.iterator(); while(it.hasNext()){ OnClickEventListener li = it.next(); li.onClick(this); } } @Override public void longClickEvent() { // TODO Auto-generated method stub Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator(); while(it.hasNext()){ OnLongClickEventListener li = it.next(); li.onLongClick(this); } } public interface OnClickEventListener { public void onClick (Widget source); } public interface OnLongClickEventListener { public void onLongClick (Widget source); } public void setOnClickEventListner(OnClickEventListener li){ mClickEventListener.add(li); } public void setOnLongClickEventListner(OnLongClickEventListener li){ mLongClickEventListener.add(li); } } 

类button

 public class Button extends Widget{ private String mButtonText; public Button (){ } public String getButtonText() { return mButtonText; } public void setButtonText(String buttonText) { this.mButtonText = buttonText; } } 

类checkbox

 public class CheckBox extends Widget{ private boolean checked; public CheckBox() { checked = false; } public boolean isChecked(){ return (checked == true); } public void setCheck(boolean checked){ this.checked = checked; } } 

活动类

包com.som_itsolutions.training.java.exampleeventlistener;

 public class Activity implements Widget.OnClickEventListener { public Button mButton; public CheckBox mCheckBox; private static Activity mActivityHandler; public static Activity getActivityHandle(){ return mActivityHandler; } public Activity () { mActivityHandler = this; mButton = new Button(); mButton.setOnClickEventListner(this); mCheckBox = new CheckBox(); mCheckBox.setOnClickEventListner(this); } public void onClick (Widget source) { if(source == mButton){ mButton.setButtonText("Thank you for clicking me..."); System.out.println(((Button) mButton).getButtonText()); } if(source == mCheckBox){ if(mCheckBox.isChecked()==false){ mCheckBox.setCheck(true); System.out.println("The checkbox is checked..."); } else{ mCheckBox.setCheck(false); System.out.println("The checkbox is not checked..."); } } } public void doSomeWork(Widget source){ source.clickEvent(); } } 

其他类

 public class OtherClass implements Widget.OnClickEventListener{ Button mButton; public OtherClass(){ mButton = Activity.getActivityHandle().mButton; mButton.setOnClickEventListner(this);//interested in the click event //of the button } @Override public void onClick(Widget source) { if(source == mButton){ System.out.println("Other Class has also received the event notification..."); } } 

主要类

 public class Main { public static void main(String[] args) { // TODO Auto-generated method stub Activity a = new Activity(); OtherClass o = new OtherClass(); a.doSomeWork(a.mButton); a.doSomeWork(a.mCheckBox); } } 

从上面的代码可以看出,我们有一个名为events的接口,它基本上列出了我们的应用程序可能发生的所有事件。 Widget类是所有UI组件(如Button,Checkbox)的基类。 这些UI组件是实际从框架代码接收事件的对象。 Widget类实现了Events接口,它也有两个嵌套的接口,即OnClickEventListener和OnLongClickEventListener

这两个接口负责监听Widget派生UI组件(如Button或Checkbox)上可能发生的事件。 因此,如果我们将此示例与使用Java接口的早期callback示例进行比较,则这两个接口将用作callback接口。 所以更高层次的代码(Here Activity)实现了这两个接口。 每当一个事件发生的时候,就会调用更高层次的代码(或者更高层次代码中实现的这些接口的方法,这里就是Activity)。

现在让我来讨论Callback和Eventlistener模式之间的基本区别。 正如我们所提到的,使用回叫,被叫可以只通知一个主叫。 但是对于EventListener模式,应用程序的任何其他部分或类都可以注册Button或Checkbox上可能发生的事件。 这种类的例子是OtherClass。 如果你看到OtherClass的代码,你会发现它已经注册了一个ClickEvent的监听器,这个监听器可能发生在Activity中定义的Button中。 有趣的部分是,除了Activity(调用者)之外,这个OtherClass也会在Button上发生点击事件时得到通知。

一个重要的用法是将一个函数注册为句柄(即callback函数),然后发送一个消息/调用某个函数来完成一些工作或处理。 现在处理完成后,被调用的函数会调用我们的注册函数(即现在callback完成),从而指示我们处理完成。
这个维基百科链接解释得非常好,graphics。

callback函数,也称为高阶函数,是作为parameter passing给另一个函数的函数,callback函数在父函数内被调用(或执行)。

 $("#button_1").click(function() { alert("button 1 Clicked"); }); 

这里我们传递一个函数作为click方法的参数。 click方法将调用(或执行)我们传递给它的callback函数。

什么是callback

电话比喻 :打电话给某人打电话给我们。

callback函数是一段可执行代码,作为parameter passing给其他代码,在某个方便的时候,这个代码可以callback(执行)参数。

有关在wiki上callback的更多信息

什么是callback函数

callback函数是一个传递给另一个函数的函数(让我们把这个函数作为其他函数)作为一个参数,callback函数在其他函数中调用(或执行)。