如何用简单的英语解释回调?它们与从另一个函数调用一个函数有什么不同?

时间:2022-04-09 15:59:33

How to explain callbacks in plain English? How are they different from calling one function from another function taking some context from the calling function? How can their power be explained to a novice programmer?

如何用简单的英语解释回调?它们与从另一个函数调用一个函数与调用函数的上下文有什么不同?他们的权力如何被解释给一个新手程序员?

32 个解决方案

#1


108  

Often an application needs to execute different functions based upon its context/state. For this, we use a variable where we would store the information about the function to be called. ‪According to its need the application will set this variable with the information about function to be called and will call the function using the same variable.

通常,应用程序需要根据其上下文/状态来执行不同的功能。为此,我们使用一个变量来存储要调用的函数的信息。‪根据其需要应用程序将设置此变量的函数被称为信息并将调用该函数使用相同的变量。

In javascript, the example is below. Here we use method argument as a variable where we store information about function.

在javascript中,示例如下。这里我们使用方法参数作为变量存储关于函数的信息。

function processArray(arr, callback) {
    var resultArr = new Array(); 
    for (var i = arr.length-1; i >= 0; i--)
        resultArr[i] = callback(arr[i]);
    return resultArr;
}

var arr = [1, 2, 3, 4];
var arrReturned = processArray(arr, function(arg) {return arg * -1;});
// arrReturned would be [-1, -2, -3, -4]

#2


451  

I am going to try to keep this dead simple. A "callback" is any function that is called by another function which takes the first function as a parameter. A lot of the time, a "callback" is a function that is called when something happens. That something can be called an "event" in programmer-speak.

我要尽量保持这个简单。“回调”是由另一个函数调用的函数,该函数将第一个函数作为参数。很多时候,一个“回调”是一个函数,当某个事件发生时调用它。在编程语言中,可以称之为“事件”。

Imagine this scenario: you are expecting a package in a couple of days. The package is a gift for your neighbor. Therefore, once you get the package, you want it brought over to the neighbors. You are out of town, and so you leave instructions for your spouse.

想象一下这样的场景:您将在几天内收到一个包。这个包裹是送给你邻居的礼物。因此,一旦你拿到了包裹,你就想把它带到邻居那里。你出城了,所以你给你的配偶留下指示。

You could tell them to get the package and bring it to the neighbors. If your spouse was as stupid as a computer, they would sit at the door and wait for the package until it came (NOT DOING ANYTHING ELSE) and then once it came they would bring it over to the neighbors. But there's a better way. Tell your spouse that ONCE they receive the package, they should bring it over the neighbors. Then, they can go about life normally UNTIL they receive the package.

你可以告诉他们把包裹拿到邻居那里。如果你的配偶和电脑一样愚蠢,他们会坐在门口等待包裹,直到它到来(而不是做别的事情),然后一旦它来了,他们就会把它带到邻居那里。但是有一个更好的方法。告诉你的配偶,一旦他们收到了包裹,他们应该把它带到邻居那里。然后,他们可以正常生活直到收到包裹。

In our example, the receiving of the package is the "event" and the bringing it to the neighbors is the "callback". Your spouse "runs" your instructions to bring the package over only when the package arrives. Much better!

在我们的示例中,接收包是“事件”,而将其引入到邻居中是“回调”。你的配偶“运行”你的指令,只在包裹到达时才把包裹带过来。更好的!

This kind of thinking is obvious in daily life, but computers don't have the same kind of common sense. Consider how programmers normally write to a file:

这种想法在日常生活中是很明显的,但是电脑却没有同样的常识。考虑程序员通常如何编写文件:

fileObject = open(file)
# now that we have WAITED for the file to open, we can write to it
fileObject.write("We are writing to the file.")
# now we can continue doing the other, totally unrelated things our program does

Here, we WAIT for the file to open, before we write to it. This "blocks" the flow of execution, and our program cannot do any of the other things it might need to do! What if we could do this instead:

在这里,我们等待文件打开,然后再写入。这“阻塞”了执行流,而我们的程序不能执行它可能需要做的任何其他事情!如果我们可以这样做:

# we pass writeToFile (A CALLBACK FUNCTION!) to the open function
fileObject = open(file, writeToFile)
# execution continues flowing -- we don't wait for the file to be opened
# ONCE the file is opened we write to it, but while we wait WE CAN DO OTHER THINGS!

It turns out we do this with some languages and frameworks. It's pretty cool! Check out Node.js to get some real practice with this kind of thinking.

我们用一些语言和框架来做这个。它很酷!查看节点。js通过这种思考来获得一些实际的练习。

#3


76  

How to explain callbacks in plain English?

如何用简单的英语解释回调?

In plain English, a callback function is like a Worker who "calls back" to his Manager when he has completed a Task.

在简单的英语中,回调函数就像一个工作人员在完成任务后“回电话”给他的经理。

How are they different from calling one function from another function taking some context from the calling function?

它们与从另一个函数调用一个函数与调用函数的上下文有什么不同?

It is true that you are calling a function from another function, but the key is that the callback is treated like an Object, so you can change which Function to call based on the state of the system (like the Strategy Design Pattern).

确实,您从另一个函数调用了一个函数,但是关键是回调被当作一个对象处理,因此您可以根据系统的状态(比如策略设计模式)更改调用的函数。

How can their power be explained to a novice programmer?

他们的权力如何被解释给一个新手程序员?

The power of callbacks can easily be seen in AJAX-style websites which need to pull data from a server. Downloading the new data may take some time. Without callbacks, your entire User Interface would "freeze up" while downloading the new data, or you would need to refresh the entire page rather than just part of it. With a callback, you can insert a "now loading" image and replace it with the new data once it is loaded.

回调的力量很容易在ajax风格的网站上看到,这些网站需要从服务器获取数据。下载新数据可能需要一些时间。如果没有回调,您的整个用户界面将在下载新数据时“冻结”,或者您需要刷新整个页面,而不仅仅是一部分。通过回调,您可以插入一个“现在加载”图像,并在加载新数据后替换它。

Some code without a callback:

function grabAndFreeze() {
    showNowLoading(true);
    var jsondata = getData('http://yourserver.com/data/messages.json');
    /* User Interface 'freezes' while getting data */
    processData(jsondata);
    showNowLoading(false);
    do_other_stuff(); // not called until data fully downloaded
}

function processData(jsondata) { // do something with the data
   var count = jsondata.results ? jsondata.results.length : 0;
   $('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
   $('#results_messages').html(jsondata.results || '(no new messages)');
}

With Callback:

Here is an example with a callback, using jQuery's getJSON:

下面是一个使用jQuery getJSON的回调函数示例:

function processDataCB(jsondata) { // callback: update UI with results
   showNowLoading(false);
   var count = jsondata.results ? jsondata.results.length : 0;
   $('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
   $('#results_messages').html(jsondata.results || '(no new messages)');
}

function grabAndGo() { // and don't freeze
    showNowLoading(true);
    $('#results_messages').html(now_loading_image);
    $.getJSON("http://yourserver.com/data/messages.json", processDataCB);
    /* Call processDataCB when data is downloaded, no frozen User Interface! */
    do_other_stuff(); // called immediately
}

With Closure:

Often the callback needs to access state from the calling function using a closure, which is like the Worker needing to get information from the Manager before he can complete his Task. To create the closure, you can inline the function so it sees the data in the calling context:

通常,回调需要使用闭包从调用函数访问状态,这就像工作人员在完成任务之前需要从管理器获取信息一样。要创建闭包,可以内联该函数,以便在调用上下文中看到数据:

/* Grab messages, chat users, etc by changing dtable. Run callback cb when done.*/
function grab(dtable, cb) { 
    if (null == dtable) { dtable = "messages"; }
    var uiElem = "_" + dtable;
    showNowLoading(true, dtable);
    $('#results' + uiElem).html(now_loading_image);
    $.getJSON("http://yourserver.com/user/"+dtable+".json", cb || function (jsondata) {
       // Using a closure: can "see" dtable argument and uiElem variables above.
       var count = jsondata.results ? jsondata.results.length : 0, 
           counterMsg = ['Fetched', count, 'new', dtable].join(' '),
           // no new chatters/messages/etc
           defaultResultsMsg = ['(no new ', dtable, ')'].join(''); 
       showNowLoading(false, dtable);
       $('#counter' + uiElem).text(counterMsg);
       $('#results'+ uiElem).html(jsondata.results || defaultResultsMsg);
    });
    /* User Interface calls cb when data is downloaded */

    do_other_stuff(); // called immediately
}

Usage:

// update results_chatters when chatters.json data is downloaded:
grab("chatters"); 
// update results_messages when messages.json data is downloaded
grab("messages"); 
// call myCallback(jsondata) when "history.json" data is loaded:
grab("history", myCallback); 

Closure

Finally, here is a definition of closure from Douglas Crockford:

最后,这是道格拉斯·克罗克福德的封闭性定义:

Functions can be defined inside of other functions. The inner function has access to the vars and parameters of the outer function. If a reference to an inner function survives (for example, as a callback function), the outer function's vars also survive.

函数可以在其他函数中定义。内部函数可以访问外部函数的vars和参数。如果引用一个内部函数(例如,作为一个回调函数),外部函数的vars也会存在。

See also:

参见:

#4


29  

I'm stunned to see so many intelligent people failing to stress the reality that the word "callback" has come to be used in two inconsistent ways.

看到这么多聪明的人没能强调“回调”这个词被用在两种不一致的方式上,我感到震惊。

Both ways involve the customization of a function by passing additional functionality (a function definition, anonymous or named) to an existing function. ie.

这两种方法都包括通过将附加功能(函数定义、匿名或命名)传递给现有函数来定制函数。ie。

customizableFunc(customFunctionality)

If the custom functionality is simply plugged into the code block, you have customized the function, like so.

如果定制的功能只是插入到代码块中,那么您已经定制了该函数,就像这样。

    customizableFucn(customFunctionality) {
      var data = doSomthing();
      customFunctionality(data);
      ...
    }

Though this kind of injected functionality is often called a "callback", there is nothing contingent about it. A very obvious example is the forEach method in which a custom function is supplied as an argument to be applied to each element in an array to modify the array.

尽管这种注入的功能通常被称为“回调”,但它并没有什么偶然的。一个非常明显的例子是forEach方法,它提供了一个自定义函数作为参数来应用于数组中的每个元素以修改数组。

But this is fundamentally distinct from the use of "callback" functions for asynchronous programming, as in AJAX or node.js or simply in assigning functionality to user interaction events (like mouse clicks). In this case, the whole idea is to wait for a contingent event to occur before executing the custom functionality. This is obvious in the case of user interaction, but is also important in i/o (input/output) processes that can take time, like reading files from disk. This is where the term "callback" makes the most obvious sense. Once an i/o process is started (like asking for a file to be read from disk or a server to return data from an http request) an asynchronous program doesn't wait around for it to finish. It can go ahead with whatever tasks are scheduled next, and only respond with the custom functionality after it has been notified that the read file or http request is completed (or that it failed) and that the data is available to the custom functionality. It's like calling a business on the phone and leaving your "callback" number, so they can call you when someone is available to get back to you. That's better than hanging on the line for who knows how long and not being able to attend to other affairs.

但这与异步编程(如AJAX或node)中的“回调”函数的使用截然不同。js或简单地将功能分配给用户交互事件(如鼠标点击)。在这种情况下,整个想法是在执行定制功能之前等待一个偶然事件发生。在用户交互的情况下,这一点很明显,但是在输入/输出过程中也很重要,这需要时间,就像从磁盘读取文件一样。这就是“回调”一词最明显的意义所在。一旦启动了i/o进程(比如请求从磁盘读取文件或服务器从http请求返回数据),异步程序就不会等待它完成。它可以继续执行下一项任务,并且只在被通知读取文件或http请求完成(或者它失败了)和数据对自定义功能可用之后才响应定制的功能。这就像打电话给一个公司,留下你的“回调”号码,这样他们就可以在有人回来找你的时候给你打电话。这总比挂在电话上好,因为谁知道有多少时间不能处理其他事情。

Asynchronous use inherently involves some means of listening for the desired event (e.g, the completion of the i/o process) so that, when it occurs (and only when it occurs) the custom "callback" functionality is executed. In the obvious AJAX example, when the data actually arrives from the server, the "callback" function is triggered to use that data to modify the DOM and therefore redraw the browser window to that extent.

异步使用本身包含了一些侦听所需事件的方法(e)。i/o进程的完成,当它发生时(并且只有当它发生时),定制的“回调”功能才会被执行。在明显的AJAX示例中,当数据实际来自服务器时,“回调”函数被触发,以使用该数据修改DOM,从而在此范围内重新绘制浏览器窗口。

To recap. Some people use the word "callback" to refer to any kind of custom functionality that can be injected into an existing function as an argument. But, at least to me, the most appropriate use of the word is where the injected "callback" function is used asynchronously -- to be executed only upon the occurrence of an event that it is waiting to be notified of.

回顾一下。有些人使用“回调”这个词来指代任何一种自定义功能,这些功能可以被注入到现有函数中作为参数。但是,至少对我来说,最恰当地使用这个词的地方是,注入的“回调”函数被异步地使用——只在它等待被通知的事件发生时被执行。

#5


25  

In non-programmer terms, a callback is a fill-in-the-blank in a program.

在非程序员术语中,回调是程序中的填空。

A common item on many paper forms is "Person to call in case of emergency". There is a blank line there. You write in someone's name and phone number. If an emergency occurs, then that person gets called.

许多纸质表格上的一个常见项目是“紧急情况下打电话的人”。这里有一条空行。你用别人的名字和电话来写。如果发生紧急情况,那么这个人就会被呼叫。

  • Everyone gets the same blank form, but
  • 每个人都有相同的空白表格,但是。
  • Everyone can write a different emergency contact number.
  • 每个人都可以写一个不同的紧急联系电话。

This is key. You do not change the form (the code, usually someone else's). However you can fill in missing pieces of information (your number).

这是关键。您不会更改表单(代码,通常是其他人的)。然而,你可以填写丢失的信息(你的号码)。

Example 1:

示例1:

Callbacks are used as customized methods, possibly for adding to/changing a program's behavior. For example, take some C code that performs a function, but does not know how to print output. All it can do is make a string. When it tries to figure out what to do with the string, it sees a blank line. But, the programmer gave you the blank to write your callback in!

回调被用作定制的方法,可能是为了增加/改变一个程序的行为。例如,使用一些执行函数的C代码,但不知道如何打印输出。它所能做的就是做一个字符串。当它试图弄清楚如何处理字符串时,它会看到一个空行。但是,程序员给了你空白写回你的回叫!

In this example, you do not use a pencil to fill in a blank on a sheet of paper, you use the function set_print_callback(the_callback).

在本例中,您不用铅笔在一张纸上填写空白,您可以使用函数set_print_callback(the_callback)。

  • The blank variable in the module/code is the blank line,
  • 模块/代码中的空白变量为空行,
  • set_print_callback is the pencil,
  • set_print_callback是铅笔,
  • and the_callback is your information you are filling in.
  • 而the_callback是你填写的信息。

You've now filled in this blank line in the program. Whenever it needs to print output, it will look at that blank line, and follow the instructions there (i.e. call the function you put there.) Practically, this allows the possibility of printing to screen, to a log file, to a printer, over a network connection, or any combination thereof. You have filled in the blank with what you want to do.

您现在已经在程序中填充了这个空行。当它需要打印输出时,它会查看那个空行,并按照那里的指令(即调用你放在那里的函数)。实际上,这允许打印屏幕、日志文件、打印机、网络连接或其任何组合的可能性。你已经填满了你想做的事。

Example 2:

示例2:

When you get told you need to call an emergency number, you go and read what is written on the paper form, and then call the number you read. If that line is blank nothing will be done.

当你被告知需要拨打一个紧急电话号码时,你可以去读一下纸上写的内容,然后拨打你所读的电话号码。如果这条线是空的,什么也不会做。

Gui programming works much the same way. When a button is clicked, the program needs to figure out what to do next. It goes and looks for the callback. This callback happens to be in a blank labeled "Here's what you do when Button1 is clicked"

Gui编程的工作方式也大致相同。当一个按钮被点击,程序需要知道下一步该做什么。它去寻找回调函数。这个回调恰好是在一个空白的标签中"这是当Button1被点击时你所做的"

Most IDEs will automatically fill in the blank for you (write the basic method) when you ask it to (e.g. button1_clicked). However that blank can have any method you darn well please. You could call the method run_computations or butter_the_biscuits as long as you put that callback's name in the proper blank. You could put "555-555-1212" in the emergency number blank. It doesn't make much sense, but it's permissible.

大多数ide会在你要求它(例如button1_click)的时候自动填充你的空白(写基本的方法)。但是,这个空白可以有任何方法,请。只要将回调的名称放在适当的空白中,就可以调用方法run_compution或butter_the_biscuits。你可以把“555-555-1212”放在紧急号码栏里。这没有多大意义,但这是允许的。


Final note: That blank line that you're filling in with the callback? It can be erased and re-written at will. (whether you should or not is another question, but that is a part of their power)

最后注意:你填入回调的那个空行?它可以被删除和重写。(不管你是否应该,这是另一个问题,但这是他们力量的一部分)

#6


20  

Johny the programmer needs a stapler, so he goes down to the office supply department and ask for one, after filling the request form he can either stand there and wait for the clerk go look around the warehouse for the stapler (like a blocking function call) or go do something else meantime.

约翰尼程序员需要一个订书机,所以他走到办公用品部门要求,填写申请表后,他可以站在那里,等待订书机的职员去看看仓库(如阻塞函数调用)或去做别的事情。

since this usually takes time, johny puts a note together with the request form asking them to call him when the stapler is ready for pickup, so meantime he can go do something else like napping on his desk.

因为这通常需要时间,johny把一张纸条和请求表格一起,让他们在订书机准备好了的时候给他打电话,这样他就可以去做一些其他的事情,比如在他的桌子上打盹。

#7


19  

Always better to start with an example :).

最好从一个例子开始:)。

Let's assume you have two modules A and B.

假设你有两个模块A和B。

You want module A to be notified when some event/condition occurs in module B. However, module B has no idea about your module A. All it knows is an address to a particular function (of module A) through a function pointer that is provided to it by module A.

您希望模块A在某些事件/条件发生时得到通知。但是,模块B不知道您的模块A。它所知道的是通过一个由模块A提供给它的函数指针对特定函数(模块A)的一个地址。

So all B has to do now, is "callback" into module A when a particular event/condition occurs by using the function pointer. A can do further processing inside the callback function.

所以B现在必须做的是,当一个特定的事件/条件通过函数指针发生时,“回调”到模块A中。可以在回调函数中进行进一步的处理。

*) A clear advantage here is that you are abstracting out everything about module A from module B. Module B does not have to care who/what module A is.

这里有一个明显的优点,就是你可以从模块B中抽象出所有关于模块A的内容。B模块不需要关心A模块是什么。

#8


16  

Imagine you need a function that returns 10 squared so you write a function:

假设你需要一个函数返回10的平方所以你写一个函数

function tenSquared() {return 10*10;}

Later you need 9 squared so you write another function:

之后你需要9的平方所以你写另一个函数

function nineSquared() {return 9*9;}

Eventually you will replace all of these with a generic function:

最终你会用一个通用的函数来替换所有这些:

function square(x) {return x*x;}

The exact same thinking applies for callbacks. You have a function that does something and when done calls doA:

同样的想法也适用于回调。你有一个函数,它做了一些事情,当完成调用doA:

function computeA(){
    ...
    doA(result);
}

Later you want the exact same function to call doB instead you could duplicate the whole function:

稍后,你需要完全相同的函数调用doB,你可以复制整个函数:

function computeB(){
    ...
    doB(result);
}

Or you could pass a callback function as a variable and only have to have the function once:

或者可以将回调函数作为变量传递,只需要有一次函数:

function compute(callback){
    ...
    callback(result);
}

Then you just have to call compute(doA) and compute(doB).

然后只需调用compute(doA)和compute(doB)。

Beyond simplifying code, it lets asynchronous code let you know it has completed by calling your arbitrary function on completion, similar to when you call someone on the phone and leave a callback number.

除了简化代码之外,它还允许异步代码通过在完成时调用您的任意函数来完成,类似于您在电话中调用某人并留下一个回调号。

#9


10  

You feel ill so you go to the doctor. He examines you and determines you need some medication. He prescribes some meds and calls the prescription into your local pharmacy. You go home. Later your pharmacy calls to tell you your prescription is ready. You go and pick it up.

你觉得不舒服,就去看医生。他检查你,确定你需要一些药物。他开了一些药,并把处方开到你当地的药房。你回家了。后来你的药店打电话告诉你你的处方已经准备好了。你去把它捡起来。

#10


9  

There's two points to explain, one is how a callback works (passing around a function that can be called without any knowledge of its context), the other what it's used for (handling events asynchronously).

有两点需要解释,一个是回调是如何工作的(传递一个可以在不了解其上下文的情况下调用的函数),另一个是它的用途(异步处理事件)。

The analogy of waiting for a parcel to arrive that has been used by other answers is a good one to explain both. In a computer program, you would tell the computer to expect a parcel. Ordinarily, it would now sit there and wait (and do nothing else) until the parcel arrives, possibly indefinitely if it never arrives. To humans, this sounds silly, but without further measures, this is totally natural to a computer.

等待一个包裹到达的类比,已经被其他答案所使用,这是一个很好的解释。在电脑程序中,你会告诉电脑要寄包裹。通常情况下,它会一直呆在那里等待,直到包裹到达,如果它永远不会到达的话,可能是无限期的。对人类来说,这听起来很傻,但如果没有进一步的措施,这对计算机来说是完全自然的。

Now the callback would be the bell at your front door. You provide the parcel service with a way to notify you of the parcel's arrival without them having to know where (even if) you are in the house, or how the bell works. (For instance, some "bells" actually dispatch a phone call.) Because you provided a "callback function" that can be "called" at any time, out of context, you can now stop sitting at the front porch and "handle the event" (of parcel arrival) whenever it's time.

现在回调就是你家前门的门铃了。你提供包裹服务的方式是通知你包裹的到达,而不需要他们知道你在哪里(即使你在房子里),或者门铃是如何工作的。(例如,一些“铃声”实际上是在发送一个电话。)因为您提供了一个“回调函数”,可以在任何时候被“调用”,在上下文之外,您现在可以停止坐在前门廊和“处理事件”(包裹到达)的时间。

#11


6  

Imagine a friend is leaving your house, and you tell her "Call me when you get home so that I know you arrived safely"; that is (literally) a call back. That's what a callback function is, regardless of language. You want some procedure to pass control back to you when it has completed some task, so you give it a function to use to call back to you.

想象一个朋友离开你的家,你告诉她“回家后给我打电话,这样我就知道你安全到达了”;这是(字面上的)回调。这就是回调函数,不管语言是什么。当它完成了一些任务时,您需要一些过程来将控制权传递给您,因此您给它一个函数来调用返回给您。

In Python, for example,

在Python中,例如,

grabDBValue( (lambda x: passValueToGUIWindow(x) ))

grabDBValue could be written to only grab a value from a database and then let you specify what to actually do with the value, so it accepts a function. You don't know when or if grabDBValue will return, but if/when it does, you know what you want it to do. Here, I pass in an anonymous function (or lambda) that sends the value to a GUI window. I could easily change the behavior of the program by doing this:

可以编写grabDBValue来从数据库中获取一个值,然后让您指定如何处理该值,因此它接受一个函数。您不知道何时或如果grabDBValue将返回,但是如果/当它发生时,您知道您想要它做什么。这里,我传入一个匿名函数(或lambda),该函数将值发送到GUI窗口。我可以很容易地改变程序的行为:

grabDBValue( (lambda x: passToLogger(x) ))

Callbacks work well in languages where functions are first class values, just like the usual integers, character strings, booleans, etc. In C, you can "pass" a function around by passing around a pointer to it and the caller can use that; in Java, the caller will ask for a static class of a certain type with a certain method name since there are no functions ("methods," really) outside of classes; and in most other dynamic languages you can just pass a function with simple syntax.

回调函数在函数为一级值的语言中工作得很好,就像通常的整数、字符字符串、布尔值等等。在C中,通过传递一个指针来传递函数,调用者可以使用它;在Java中,调用者将要求具有特定方法名称的特定类型的静态类,因为在类之外没有函数(“方法”,真的);在大多数其他的动态语言中,你可以通过简单的语法传递函数。

Protip:

In languages with lexical scoping (like Scheme or Perl) you can pull a trick like this:

在使用词汇范围(如Scheme或Perl)的语言中,您可以使用如下方法:

my $var = 2;
my $val = someCallerBackFunction(sub callback { return $var * 3; });
# Perlistas note: I know the sub doesn't need a name, this is for illustration

$val in this case will be 6 because the callback has access to the variables declared in the lexical environment where it was defined. Lexical scope and anonymous callbacks are a powerful combination warranting further study for the novice programmer.

在此情况下,$val将是6,因为回调可以访问定义它的词汇环境中声明的变量。词汇范围和匿名回调是对初学者进行进一步研究的有力组合。

#12


6  

You have some code you want to run. Normally, when you call it you are then waiting for it to be finished before you carry on (which can cause your app to go grey/produce a spinning time for a cursor).

你有一些你想要运行的代码。通常,当你调用它的时候,你会等待它在你继续之前完成(这可能会导致你的应用程序变灰/为光标产生旋转时间)。

An alternative method is to run this code in parallel and carry on with your own work. But what if your original code needs to do different things depending on the response from the code it called? Well, in that case you can pass in the name/location of the code you want it to call when it's done. This is a "call back".

另一种方法是并行运行此代码,并继续您自己的工作。但是,如果您的原始代码需要根据它所调用的代码的响应来做不同的事情呢?那么,在这种情况下,您可以传递您希望它在完成时调用的代码的名称/位置。这是“回电”。

Normal code: Ask for Information->Process Information->Deal with results of Processing->Continue to do other things.

正常代码:要求信息->过程信息->处理结果->继续做其他事情。

With callbacks: Ask for Information->Process Information->Continue to do other things. And at some later point->Deal with results of Processing.

使用回调:请求信息->过程信息->继续做其他事情。在后来的一些时候,>处理了处理结果。

#13


6  

Without callback neither others special programming resources (like threading, and others), a program is exactly a sequence of instructions which are executed sequentially one after the other, and even with a kind of "dynamic behavior" determined by certain conditions, all possible scenarios shall be previously programmed.

如果没有回调其他的特殊编程资源(如线程和其他),程序就是按顺序依次执行的指令序列,即使是在某些条件下确定的“动态行为”,所有可能的场景都应该预先编程。

So, If we need to provide a real dynamic behavior to a program we can use callback. With callback you can instructs by parameters, a program to call an another program providing some previously defined parameters and can expects some results (this is the contract or operation signature), so these results can be produced/processed by third-party program which wasn't previously known.

因此,如果我们需要为程序提供一个真正的动态行为,我们可以使用回调。有了回调,您可以通过参数指示一个程序,该程序可以调用另一个程序,提供一些以前定义的参数,并且可以预期一些结果(这是合同或操作签名),因此这些结果可以由以前不知道的第三方程序生成/处理。

This technique is the foundation of polymorphism applied to programs, functions, objects and all others unities of code ran by computers.

该技术是应用于程序、函数、对象和所有其他由计算机运行的代码统一的多态性的基础。

The human world used as example to callback is nice explained when you are doing some job, lets suppose you are a painter (here you are the main program, that paints) and call your client sometimes to ask him to approve the result of your job, so, he decides if the picture is good (your client is the third-party program).

人类世界作为例子来调很好解释,当你做一些工作,让我们假设你是一个画家(描绘)你是主程序,有时打电话给你的客户,请他批准你的工作的结果,所以,他决定如果这张照片是好的(客户是第三方程序)。

In the above example you are a painter and "delegate" to others the job to approve the result, the picture is the parameter, and each new client (the called-back "function") changes the result of your work deciding what he wants about the picture (the decision made by the clients are the returned result from the "callback function").

在上面的例子中你是一个画家,“委托”给别人工作批准结果,图片是参数,每个新客户(召回“函数”)改变你的工作的结果决定他想要什么图片(由客户决定从"回调函数")返回的结果。

I hope this explanation can be useful.

我希望这个解释是有用的。

#14


6  

Let's pretend you were to give me a potentially long-running task: get the names of the first five unique people you come across. This might take days if I'm in a sparsely populated area. You're not really interested in sitting on your hands while I'm running around so you say, "When you've got the list, call me on my cell and read it back to me. Here's the number.".

让我们假设你给了我一个潜在的长期任务:获取你遇到的前五个独特的人的名字。如果我在人烟稀少的地区,这可能需要几天的时间。当我跑来跑去的时候,你对坐在你的手上不感兴趣,所以你说:“当你拿到清单的时候,打电话给我,把它读给我听。”这是数字。”。

You've given me a callback reference--a function that I'm supposed to execute in order to hand off further processing.

您已经给了我一个回调引用——一个我应该执行的函数,以便进行进一步的处理。

In JavaScript it might look something like this:

在JavaScript中,它可能是这样的:

var lottoNumbers = [];
var callback = function(theNames) {
  for (var i=0; i<theNames.length; i++) {
    lottoNumbers.push(theNames[i].length);
  }
};

db.executeQuery("SELECT name " +
                "FROM tblEveryOneInTheWholeWorld " +
                "ORDER BY proximity DESC " +
                "LIMIT 5", callback);

while (lottoNumbers.length < 5) {
  playGolf();
}
playLotto(lottoNumbers);

This could probably be improved in lots of ways. E.g., you could provide a second callback: if it ends up taking longer than an hour, call the red phone and tell the person that answers that you've timed out.

这可能会在很多方面得到改善。例如,你可以提供第二个回叫:如果它结束的时间超过一个小时,打电话给那个人,告诉他你超时了。

#15


5  

A callback is a function that will be called by a second function. This second function doesn't know in advance what function it will call. So the identity of the callback function is stored somewhere, or passed to the second function as a parameter. This "identity," depending on the programming language, might be the address of the callback, or some other sort of pointer, or it might be the name of the function. The principal is the same, we store or pass some information that unambiguously identifies the function.

回调函数是由第二个函数调用的函数。第二个函数不知道它会调用什么函数。因此,回调函数的标识存储在某个地方,或者作为参数传递给第二个函数。这个“标识”,取决于编程语言,可能是回调的地址,或者其他类型的指针,或者它可能是函数的名称。主体是相同的,我们存储或传递一些明确标识函数的信息。

When the time comes, the second function can call the callback, supplying parameters depending on the circumstances at that moment. It might even choose the callback from a set of possible callbacks. The programming language must provide some kind of syntax to allow the second function to call the callback, knowing its "identity."

当时间到来时,第二个函数可以调用回调,根据当时的情况提供参数。它甚至可能从一组可能的回调中选择回调。编程语言必须提供某种语法,以允许第二个函数调用回调函数,知道它的“身份”。

This mechanism has a great many possible uses. With callbacks, the designer of a function can let it be customized by having it call whatever callbacks are provided. For example, a sorting function might take a callback as a parameter, and this callback might be a function for comparing two elements to decide which one comes first.

这种机制有许多可能的用途。通过回调,函数的设计器可以让它通过调用所提供的任何回调来定制。例如,排序函数可能将回调作为参数,而这个回调可能是比较两个元素的函数,以决定哪一个元素先出现。

By the way, depending on the programming language, the word "function" in the above discussion might be replaced by "block," "closure," "lambda," etc.

顺便说一下,根据编程语言,上面讨论中的“函数”一词可能会被“block”、“闭包”、“lambda”等取代。

#16


5  

Callbacks are most easily described in terms of the telephone system. A function call is analogous to calling someone on a telephone, asking her a question, getting an answer, and hanging up; adding a callback changes the analogy so that after asking her a question, you also give her your name and number so she can call you back with the answer. -- Paul Jakubik , "Callback Implementations in C++"

在电话系统中最容易描述回调。一个函数调用类似于打电话给某人,问她一个问题,得到一个答案,然后挂断电话;添加一个回调会改变这个类比,这样在问了她一个问题之后,你也可以告诉她你的名字和号码,这样她就可以给你回电话了。——Paul Jakubik,“c++中的回调实现”

#17


5  

Usually we sent variables to functions . Suppose you have task where the variable needs to be processed before being given as an argument - you can use callback .

通常我们把变量发送给函数。假设您有任务,在将变量作为参数给定之前,需要处理变量——您可以使用回调。

function1(var1, var2) is the usual way .

函数1(var1, var2)是通常的方法。

What if I want var2 to be processed and then sent as an argument? function1(var1, function2(var2))

如果我想要处理var2,然后作为参数发送呢?function1(var1 function2(var2))

This is one type of callback - where function2 executes some code and returns a variable back to the initial function .

这是一种回调函数——function2执行一些代码并将变量返回到初始函数。

#18


4  

A metaphorical explanation:

一个隐喻的解释:

I have a parcel I want delivered to a friend, and I also want to know when my friend receives it.

我有一个包裹要寄给一个朋友,我也想知道我的朋友什么时候收到的。

So I take the parcel to the post office and ask them to deliver it. If I want to know when my friend receives the parcel, I have two options:

所以我把包裹送到邮局,让他们送去。如果我想知道我的朋友什么时候收到包裹,我有两个选择:

(a) I can wait at the post office until it is delivered.

(a)我可以在邮局等候,直到收到为止。

(b) I will get an email when it is delivered.

(b)发送邮件时,我将收到一封邮件。

Option (b) is analogous to a callback.

选项(b)类似于回调。

#19


4  

For teaching callbacks, you have to teach the pointer first. Once the students understand the idea of pointer to a variable, idea of callbacks will get easier. Assuming you are using C/C++, these steps can be followed.

要教回调,你必须先教指针。一旦学生理解了指向变量的指针,回调的概念就会变得更容易。假设您使用的是C/ c++,可以遵循以下步骤。

  • First show your students how to use and manipulate variables using pointers alongside using the normal variable identifiers.
  • 首先向您的学生展示如何使用和操作使用指针的变量,以及使用常规变量标识符。
  • Then teach them there are things that can be done only with pointers(like passing a variable by reference).
  • 然后告诉他们,有些事情只能用指针来完成(比如通过引用传递变量)。
  • Then tell them how executable code or functions are just like some other data(or variables) in the memory. So, functions also have addresses or pointers.
  • 然后告诉他们可执行代码或函数与内存中的其他数据(或变量)是一样的。函数也有地址或指针。
  • Then show them how functions can be called with function pointers and tell these are called callbacks.
  • 然后向他们展示如何用函数指针调用函数,并告诉这些函数称为回调函数。
  • Now, the question is, why all these hassle for calling some functions? What is the benefit? Like data pointers, function pointer aka callbacks has some advantages over using normal identifiers.
  • 现在的问题是,为什么要调用一些函数呢?好处是什么?与数据指针一样,函数指针又名回调比使用普通标识符有一些优势。
  • The first one is, function identifiers or function names cannot be used as normal data. I mean, you cannot make a data structure with functions(like an array or a linked list of functions). But with callbacks, you can make an array, a linked list or use them with other data like in dictionary of key-value pairs or trees, or any other things. This is a powerful benefit. And other benefits are actually child of this one.
  • 第一个是,函数标识符或函数名不能用作正常数据。我的意思是,你不能用函数来构造一个数据结构(比如数组或函数链表)。但是有了回调,您可以创建一个数组,一个链表,或者在键值对、树或其他任何东西的字典中使用它们。这是一个强大的好处。其他的好处实际上是这个的孩子。
  • The most common use of callbacks is seen in event driver programming. Where one or more functions are executed based on some incoming signal. With callbacks, a dictionary can be maintained to map signals with callbacks. Then the input signal resolution and execution of corresponding code become much easier.
  • 最常见的回调使用是在事件驱动程序编程中。其中一个或多个函数是基于某个传入信号执行的。有了回调,就可以维护一个字典来映射带有回调的信号。然后,输入信号的分辨率和相应代码的执行变得容易得多。
  • The second use of callbacks coming in my mind is higher order functions. The functions which takes other functions as input arguments. And to send functions as arguments, we need callbacks. An example can be a function which take an array and a callback. Then it performs the callback on each of the item of the array and return the results in another array. If we pass the function a doubling callback, we get a doubled valued array. If we pass a squaring callback, we get squares. For square roots, just send appropriate callback. This cannot be done with normal functions.
  • 在我脑海中第二次使用回调函数是高阶函数。将其他函数作为输入参数的函数。要发送函数作为参数,我们需要回调。一个示例可以是一个带数组和回调的函数。然后,它在数组的每个项上执行回调,并将结果返回到另一个数组中。如果我们传递函数一个加倍回调,我们得到一个加倍值的数组。如果我们通过平方回调,就会得到平方。对于平方根,只需发送适当的回调。这不能用正常的函数来完成。

There might many more things. Involve the students and they will discover. Hope this helps.

可能还有更多的东西。让学生参与,他们会发现。希望这个有帮助。

#20


3  

In plain english a callback is a promise. Joe, Jane, David and Samantha share a carpool to work. Joe is driving today. Jane, David and Samantha have a couple of options:

在普通英语中,回调是一个承诺。乔、简、大卫和萨曼莎共用一个拼车。乔今天开车。Jane, David和Samantha有几个选择:

  1. Check the window every 5 minutes to see if Joe is out
  2. 每隔5分钟检查一下窗户,看看乔是否出去了。
  3. Keep doing their thing until Joe rings the door bell.
  4. 继续做他们的事,直到乔按门铃。

Option 1: This is more like a polling example where Jane would be stuck in a "loop" checking if Joe is outside. Jane can't do anything else in the mean time.

选项1:这更像是一个轮询示例,在这个例子中,Jane将被困在一个“循环”中,检查Joe是否在外面。简不能在平时做别的事情。

Option 2: This is the callback example. Jane tells Joe to ring her doorbell when he's outside. She gives him a "function" to ring the door bell. Joe does not need to know how the door bell works or where it is, he just needs to call that function i.e. ring the door bell when he's there.

选项2:这是回调示例。简告诉乔在他外出时按响她的门铃。她给了他一个按门铃的“功能”。乔不需要知道门铃是怎么工作的,也不需要知道它在哪里,他只需要调用那个功能,即当他在那里时按门铃。

Callbacks are driven by "events". In this example the "event" is Joe's arrival. In Ajax for example events can be "success" or "failure" of the asynchronous request and each can have the same or different callbacks.

回调是由“事件”驱动的。在这个例子中,“事件”是Joe的到达。在Ajax中,事件可以是异步请求的“成功”或“失败”,每个都可以有相同或不同的回调。

In terms of JavaScript applications and callbacks. We also need to understand "closures" and application context. What "this" refers to can easily confuse JavaScript developers. In this example within each person's "ring_the_door_bell()" method/callback there might be some other methods that each person need to do based on their morning routine ex. "turn_off_the_tv()". We would want "this" to refer to the "Jane" object or the "David" object so that each can setup whatever else they need done before Joe picks them up. This is where setting up the callback with Joe requires parodying the method so that "this" refers to the right object.

就JavaScript应用程序和回调而言。我们还需要理解“闭包”和应用程序上下文。“this”指的是容易让JavaScript开发人员迷惑的东西。在这个示例中,每个人的“ring_the_door_bell()”方法/回调中可能会有一些其他的方法,每个人都需要根据他们的早晨例程来做。“turn_off_the_tv()”。我们希望“this”指的是“Jane”对象或“David”对象,这样每个人都可以在Joe接他们之前安装他们需要的任何其他东西。在这里,与Joe一起设置回调需要对方法进行解析,以便“This”指的是正确的对象。

Hope that helps!

希望会有帮助!

#21


3  

A callback is a self-addressed stamped envelope. When you call a function, that is like sending a letter. If you want that function to call another function you provide that information in the form of a reference or address.

回调是一个自寻地址的邮票信封。当你调用一个函数时,这就像发送一个字母。如果您希望该函数调用另一个函数,则以引用或地址的形式提供该信息。

#22


3  

What Is a Callback Function?

什么是回调函数?

The simple answer to this first question is that a callback function is a function that is called through a function pointer. If you pass the pointer (address) of a function as an argument to another, when that pointer is used to call the function it points to it is said that a call back is made.

第一个问题的简单答案是,回调函数是通过函数指针调用的函数。如果将一个函数的指针(地址)传递给另一个函数,当该指针被用来调用该函数时,它指向的函数是返回的函数。

Callback function is hard to trace, but sometimes it is very useful. Especially when you are designing libraries. Callback function is like asking your user to gives you a function name, and you will call that function under certain condition.

回调函数很难跟踪,但有时它非常有用。特别是当你在设计图书馆的时候。回调函数就像让用户给你一个函数名,你会在一定条件下调用这个函数。

For example, you write a callback timer. It allows you to specified the duration and what function to call, and the function will be callback accordingly. “Run myfunction() every 10 seconds for 5 times”

例如,编写一个回调计时器。它允许您指定要调用的时间和函数,并且该函数将相应地回调。“每10秒运行myfunction() 5次”

Or you can create a function directory, passing a list of function name and ask the library to callback accordingly. “Callback success() if success, callback fail() if failed.”

或者,您可以创建一个函数目录,传递函数名列表,并要求库相应地回调。“回调成功()如果成功,回调失败()如果失败。”

Lets look at a simple function pointer example

让我们来看一个简单的函数指针示例。

void cbfunc()
{
     printf("called");
}

 int main ()
 {
                   /* function pointer */ 
      void (*callback)(void); 
                   /* point to your callback function */ 
      callback=(void *)cbfunc; 
                   /* perform callback */
      callback();
      return 0; 
}

How to pass argument to callback function?

如何将参数传递给回调函数?

Observered that function pointer to implement callback takes in void *, which indicates that it can takes in any type of variable including structure. Therefore you can pass in multiple arguments by structure.

Observered函数指针在void *中执行回调,这表明它可以接收任何类型的变量,包括结构。因此,您可以通过结构传递多个参数。

typedef struct myst
{
     int a;
     char b[10];
}myst;

void cbfunc(myst *mt) 
{
     fprintf(stdout,"called %d %s.",mt->a,mt->b); 
}

int main() 
{
       /* func pointer */
    void (*callback)(void *);       //param
     myst m;
     m.a=10;
     strcpy(m.b,"123");       
     callback = (void*)cbfunc;    /* point to callback function */
     callback(&m);                /* perform callback and pass in the param */
     return 0;   
}

#23


2  

A callback is a method that is scheduled to be executed when a condition is met.

回调是在满足条件时被调度执行的方法。

An "real world" example is a local video game store. You are waiting for Half-Life 3. Instead of going to the store every day to see if it is in, you register your email on a list to be notified when the game is available. The email becomes your "callback" and the condition to be met is the game's availability.

一个“真实世界”的例子是一个本地的视频游戏商店。你在等半辈子。与其每天去商店看看它是否在,你在一个名单上登记你的电子邮件,当游戏是可用的时候通知。电子邮件成为你的“回调”,满足的条件是游戏的可用性。

A "programmers" example is a web page where you want to perform an action when a button is clicked. You register a callback method for a button and continue doing other tasks. When/if the user cicks on the button, the browser will look at the list of callbacks for that event and call your method.

“程序员”示例是一个web页面,您希望在单击按钮时执行操作。您为一个按钮注册一个回调方法,并继续执行其他任务。当/如果用户在按钮上有cicks,浏览器将查看该事件的回调列表并调用您的方法。

A callback is a way to handle events asynchronously. You can never know when the callback will be executed, or if it will be executed at all. The advantage is that it frees your program and CPU cycles to perform other tasks while waiting for the reply.

回调是一种异步处理事件的方法。您永远不知道什么时候会执行回调,或者它是否会被执行。它的优点是可以在等待应答时释放程序和CPU周期来执行其他任务。

#24


2  

Plain and simple: A callback is a function that you give to another function, so that it can call it.

简单和简单:回调函数是您赋予另一个函数的函数,因此它可以调用它。

Usually it is called when some operation is completed. Since you create the callback before giving it to the other function, you can initialize it with context information from the call site. That is why it is named a call*back* - the first function calls back into the context from where it was called.

通常在某些操作完成时调用。由于在将回调函数赋给另一个函数之前创建了回调函数,因此可以从调用站点的上下文信息初始化它。这就是为什么它被命名为call*back*——第一个函数调用从它被调用的地方返回的上下文。

#25


2  

I think it's an rather easy task to explain.

我认为这是一个相当容易解释的任务。

At first callback are just ordinary functions.
And the further is, that we call this function (let's call it A) from inside another function (let's call it B).

第一次回调只是普通的函数。更进一步,我们把这个函数(我们称之为A)从另一个函数中调用(我们叫它B)

The magic about this is that I decide, which function should be called by the function from outside B.

关于这一点的神奇之处在于,我决定,函数应该由外部B的函数来调用。

At the time I write the function B I don't know which callback function should be called. At the time I call function B I also tell this function to call function A. That is all.

在编写函数B时,我不知道应该调用哪个回调函数。在我调用函数B的时候,我也告诉这个函数调用函数a,这就是全部。

#26


2  

“In computer programming, a callback is a reference to executable code, or a piece of executable code, that is passed as an argument to other code. This allows a lower-level software layer to call a subroutine (or function) defined in a higher-level layer.” - Wikipedia

在计算机编程中,回调是对可执行代码或可执行代码的引用,作为对其他代码的参数传递。这使得底层的软件层可以调用在高级层中定义的子程序(或函数)。”——*

Callback in C using Function Pointer

使用函数指针在C中回调。

In C, callback is implemented using Function Pointer. Function Pointer - as the name suggests, is a pointer to a function.

在C中,回调是使用函数指针实现的。函数指针——顾名思义,是指向函数的指针。

For example, int (*ptrFunc) ();

例如,int (*ptrFunc) ();

Here, ptrFunc is a pointer to a function that takes no arguments and returns an integer. DO NOT forget to put in the parenthesis, otherwise the compiler will assume that ptrFunc is a normal function name, which takes nothing and returns a pointer to an integer.

这里,ptrFunc是一个指向函数的指针,该函数不接受参数并返回整数。不要忘记插入括号,否则编译器会假设ptrFunc是一个正常的函数名,它不带任何东西,并返回一个指向整数的指针。

Here is some code to demonstrate the function pointer.

下面是演示函数指针的代码。

#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;
}

Now let us try to understand the concept of Callback in C using function pointer.

现在让我们试着用函数指针来理解回调函数的概念。

The complete program has three files: callback.c, reg_callback.h and reg_callback.c.

完整的程序有三个文件:回调。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)();                               
}

If we run this program, the output will be

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

This is a program demonstrating function callback inside register_callback inside my_callback back inside main program

这是一个在主程序内的my_callback内部的register_callback内演示函数回调的程序。

The higher layer function calls a lower layer function as a normal call and the callback mechanism allows the lower layer function to call the higher layer function through a pointer to a callback function.

上层函数调用底层函数作为普通调用,而回调机制允许底层函数通过指向回调函数的指针调用更高的层函数。

Callback in Java Using Interface

在Java中使用接口回调。

Java does not have the concept of function pointer It implements Callback mechanism through its Interface mechanism Here instead of a function pointer, we declare an Interface having a method which will be called when the callee finishes its task

Java没有函数指针的概念,它通过它的接口机制来实现回调机制,而不是一个函数指针,我们声明一个接口有一个方法,当callee完成它的任务时,它将被调用。

Let me demonstrate it through an example:

让我通过一个例子来证明:

The Callback Interface

回调接口

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

The Caller or the Higher Level Class

调用者或高级类。

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
}
}

The Callee or the lower layer function

Callee或下层的函数。

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 Using EventListener pattern

回调使用EventListener模式

  • List item
  • 列表项

This pattern is used to notify 0 to n numbers of Observers/Listeners that a particular task has finished

此模式用于将特定任务已完成的观察者/侦听器通知0到n。

  • List item
  • 列表项

The difference between Callback mechanism and EventListener/Observer mechanism is that in callback, the callee notifies the single caller, whereas in Eventlisener/Observer, the callee can notify anyone who is interested in that event (the notification may go to some other parts of the application which has not triggered the task)

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

Let me explain it through an example.

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

The Event Interface

事件接口

public interface Events {

public void clickEvent();
public void longClickEvent();
}

Class Widget

类部件

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);
    }
}

Class Button

类按钮

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

Class 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;
}
}

Activity Class

Activity类

package com.som_itsolutions.training.java.exampleeventlistener;

包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();
    }   
}

Other Class

其他类

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...");
}
}

Main Class

主类

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);
}
}

As you can see from the above code, that we have an interface called events which basically lists all the events that may happen for our application. The Widget class is the base class for all the UI components like Button, Checkbox. These UI components are the objects that actually receive the events from the framework code. Widget class implements the Events interface and also it has two nested interfaces namely OnClickEventListener & OnLongClickEventListener

正如您从上面的代码中看到的,我们有一个名为events的接口,它基本上列出了应用程序可能发生的所有事件。小部件类是所有UI组件(如按钮、复选框)的基类。这些UI组件是实际从框架代码接收事件的对象。Widget类实现了事件接口,并且它有两个嵌套的接口,即OnClickEventListener和OnLongClickEventListener。

These two interfaces are responsible for listening to events that may occur on the Widget derived UI components like Button or Checkbox. So if we compare this example with the earlier Callback example using Java Interface, these two interfaces work as the Callback interface. So the higher level code (Here Activity) implements these two interfaces. And whenever an event occurs to a widget, the higher level code (or the method of these interfaces implemented in the higher level code, which is here Activity) will be called.

这两个接口负责侦听在小部件派生的UI组件(如按钮或复选框)上可能发生的事件。因此,如果我们将这个示例与使用Java接口的早期回调示例进行比较,这两个接口作为回调接口。因此,高级代码(这里是活动)实现了这两个接口。每当一个小部件发生事件时,就会调用更高级别的代码(或者在更高级别的代码中实现的这些接口的方法)。

Now let me discuss the basic difference between Callback and Eventlistener pattern. As we have mentioned that using Callback, the Callee can notify only a single Caller. But in the case of EventListener pattern, any other part or class of the Application can register for the events that may occur on the Button or Checkbox. The example of this kind of class is the OtherClass. If you see the code of the OtherClass, you will find that it has registered itself as a listener to the ClickEvent that may occur in the Button defined in the Activity. Interesting part is that, besides the Activity ( the Caller), this OtherClass will also be notified whenever the click event occurs on the Button.

现在让我讨论回调和Eventlistener模式的基本区别。正如我们前面提到的,使用回调时,Callee可以只通知一个调用者。但在EventListener模式的情况下,应用程序的任何其他部分或类都可以注册在按钮或复选框中可能发生的事件。这种类的例子是另一个类。如果您看到其他类的代码,您会发现它已经将自己注册为一个监听器,并将其注册为在活动中定义的按钮中可能发生的ClickEvent。有趣的是,除了活动(调用者)之外,在按钮上发生单击事件时,也会通知其他类。

#27


1  

[edited]when we have two functions say functionA and functionB,if functionA depends on functionB.

[编辑]当我们有两个函数时,functionA和functionB,如果functionA依赖于functionB。

then we call functionB as a callback function.this is widely used in Spring framework.

然后我们调用functionB作为回调函数。这在Spring框架中得到了广泛的应用。

如何用简单的英语解释回调?它们与从另一个函数调用一个函数有什么不同?

#28


1  

Think of a method as giving a task to a coworker. A simple task might be the following:

把一种方法看成是给同事一个任务。一个简单的任务可能是:

Solve these equations:
x + 2 = y
2 * x = 3 * y

Your coworker diligently does the math and gives you the following result:

你的同事认真地做了计算,并给出了如下结果:

x = -6
y = -4

But your coworker has a problem, he doesn't always understand notations, such as ^, but he does understand them by their description. Such as exponent. Everytime he finds one of these you get back the following:

但是你的同事有一个问题,他并不总是理解符号,比如^,但是他也理解他们的描述。如指数。每次他发现其中的一个,你就会得到以下信息:

I don't understand "^"

This requires you to rewrite your entire instruction set again after explaining what the character means to your coworker, and he doesn't always remember in between questions. And he has difficulty remembering your tips as well, such as just ask me. He always follows your written directions as best he can however.

这就要求你在向你的同事解释这个角色的意思之后,再一次重写你的整个指令集,而且他也不总是在问题之间记得。他也很难记住你的建议,比如问我。他总是尽可能地听从你的书面指示。

You think of a solution, you just add the following to all of your instructions:

你想到一个解决方案,你只需在你的所有指令中加上以下内容:

If you have any questions about symbols, call me at extension 1234 and I will tell you its name.

Now whenever he has a problem he calls you and asks, rather than giving you a bad response and making the process restart.

现在,只要他有问题,他就会打电话问你,而不是给你一个糟糕的答复,让程序重新启动。

#29


0  

Callbacks allows you to insert your own code into another block of code to be executed at another time, that modifies or adds to the behavior of that other block of code to suit your needs. You gain flexibility and customizability while being able to have more maintainable code.

回调允许您将自己的代码插入到另一个代码块中,以便在另一个时间执行,从而修改或添加其他代码块的行为,以满足您的需要。您可以获得灵活性和可定制性,同时能够拥有更易于维护的代码。

Less hardcode = easier to maintain and change = less time = more business value = awesomeness.

更少的硬编码=更容易维护和更改=更少的时间=更多的业务价值= awesomeness。

For example, in javascript, using Underscore.js, you could find all even elements in an array like this:

例如,在javascript中,使用下划线。js,你可以在这样的数组中找到所有的元素:

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]

Example courtesy of Underscore.js: http://documentcloud.github.com/underscore/#filter

强调礼貌的示例。js:http://documentcloud.github.com/underscore/ #过滤器

#30


0  

This of it in terms of downloading a webpage:

就下载网页而言:

Your program runs on a cellphone and is requesting the webpage http://www.google.com. If you write your program synchronously, the function you write to download the data will be running continuously until all the data is download. This means your UI will not refresh and will basically appear frozen. If you write your program using callbacks, you request the data and say "execute this function when you've finished." This allows the UI to still allow user interaction while the file is downloading. Once the webpage has finished downloading, your result function (callback) is called and you can handle the data.

你的程序运行在一个手机上,并请求网页http://www.google.com。如果您同步编写程序,您编写的函数下载数据将持续运行,直到所有数据都被下载。这意味着您的UI将不会刷新,并且基本上会出现冻结。如果您使用回调编写程序,则请求数据并表示“完成后执行此函数”。这允许UI在文件下载时仍然允许用户交互。一旦网页下载完毕,你的结果函数(回调)就会被调用,你就可以处理数据了。

Basically, it allows you to request something and continue executing while waiting for the result. Once the result comes back to you via a callback function, you can pick up the operation where it left off.

基本上,它允许您在等待结果时请求某些东西并继续执行。一旦结果通过一个回调函数返回给您,您就可以在它停止的地方进行操作。

#1


108  

Often an application needs to execute different functions based upon its context/state. For this, we use a variable where we would store the information about the function to be called. ‪According to its need the application will set this variable with the information about function to be called and will call the function using the same variable.

通常,应用程序需要根据其上下文/状态来执行不同的功能。为此,我们使用一个变量来存储要调用的函数的信息。‪根据其需要应用程序将设置此变量的函数被称为信息并将调用该函数使用相同的变量。

In javascript, the example is below. Here we use method argument as a variable where we store information about function.

在javascript中,示例如下。这里我们使用方法参数作为变量存储关于函数的信息。

function processArray(arr, callback) {
    var resultArr = new Array(); 
    for (var i = arr.length-1; i >= 0; i--)
        resultArr[i] = callback(arr[i]);
    return resultArr;
}

var arr = [1, 2, 3, 4];
var arrReturned = processArray(arr, function(arg) {return arg * -1;});
// arrReturned would be [-1, -2, -3, -4]

#2


451  

I am going to try to keep this dead simple. A "callback" is any function that is called by another function which takes the first function as a parameter. A lot of the time, a "callback" is a function that is called when something happens. That something can be called an "event" in programmer-speak.

我要尽量保持这个简单。“回调”是由另一个函数调用的函数,该函数将第一个函数作为参数。很多时候,一个“回调”是一个函数,当某个事件发生时调用它。在编程语言中,可以称之为“事件”。

Imagine this scenario: you are expecting a package in a couple of days. The package is a gift for your neighbor. Therefore, once you get the package, you want it brought over to the neighbors. You are out of town, and so you leave instructions for your spouse.

想象一下这样的场景:您将在几天内收到一个包。这个包裹是送给你邻居的礼物。因此,一旦你拿到了包裹,你就想把它带到邻居那里。你出城了,所以你给你的配偶留下指示。

You could tell them to get the package and bring it to the neighbors. If your spouse was as stupid as a computer, they would sit at the door and wait for the package until it came (NOT DOING ANYTHING ELSE) and then once it came they would bring it over to the neighbors. But there's a better way. Tell your spouse that ONCE they receive the package, they should bring it over the neighbors. Then, they can go about life normally UNTIL they receive the package.

你可以告诉他们把包裹拿到邻居那里。如果你的配偶和电脑一样愚蠢,他们会坐在门口等待包裹,直到它到来(而不是做别的事情),然后一旦它来了,他们就会把它带到邻居那里。但是有一个更好的方法。告诉你的配偶,一旦他们收到了包裹,他们应该把它带到邻居那里。然后,他们可以正常生活直到收到包裹。

In our example, the receiving of the package is the "event" and the bringing it to the neighbors is the "callback". Your spouse "runs" your instructions to bring the package over only when the package arrives. Much better!

在我们的示例中,接收包是“事件”,而将其引入到邻居中是“回调”。你的配偶“运行”你的指令,只在包裹到达时才把包裹带过来。更好的!

This kind of thinking is obvious in daily life, but computers don't have the same kind of common sense. Consider how programmers normally write to a file:

这种想法在日常生活中是很明显的,但是电脑却没有同样的常识。考虑程序员通常如何编写文件:

fileObject = open(file)
# now that we have WAITED for the file to open, we can write to it
fileObject.write("We are writing to the file.")
# now we can continue doing the other, totally unrelated things our program does

Here, we WAIT for the file to open, before we write to it. This "blocks" the flow of execution, and our program cannot do any of the other things it might need to do! What if we could do this instead:

在这里,我们等待文件打开,然后再写入。这“阻塞”了执行流,而我们的程序不能执行它可能需要做的任何其他事情!如果我们可以这样做:

# we pass writeToFile (A CALLBACK FUNCTION!) to the open function
fileObject = open(file, writeToFile)
# execution continues flowing -- we don't wait for the file to be opened
# ONCE the file is opened we write to it, but while we wait WE CAN DO OTHER THINGS!

It turns out we do this with some languages and frameworks. It's pretty cool! Check out Node.js to get some real practice with this kind of thinking.

我们用一些语言和框架来做这个。它很酷!查看节点。js通过这种思考来获得一些实际的练习。

#3


76  

How to explain callbacks in plain English?

如何用简单的英语解释回调?

In plain English, a callback function is like a Worker who "calls back" to his Manager when he has completed a Task.

在简单的英语中,回调函数就像一个工作人员在完成任务后“回电话”给他的经理。

How are they different from calling one function from another function taking some context from the calling function?

它们与从另一个函数调用一个函数与调用函数的上下文有什么不同?

It is true that you are calling a function from another function, but the key is that the callback is treated like an Object, so you can change which Function to call based on the state of the system (like the Strategy Design Pattern).

确实,您从另一个函数调用了一个函数,但是关键是回调被当作一个对象处理,因此您可以根据系统的状态(比如策略设计模式)更改调用的函数。

How can their power be explained to a novice programmer?

他们的权力如何被解释给一个新手程序员?

The power of callbacks can easily be seen in AJAX-style websites which need to pull data from a server. Downloading the new data may take some time. Without callbacks, your entire User Interface would "freeze up" while downloading the new data, or you would need to refresh the entire page rather than just part of it. With a callback, you can insert a "now loading" image and replace it with the new data once it is loaded.

回调的力量很容易在ajax风格的网站上看到,这些网站需要从服务器获取数据。下载新数据可能需要一些时间。如果没有回调,您的整个用户界面将在下载新数据时“冻结”,或者您需要刷新整个页面,而不仅仅是一部分。通过回调,您可以插入一个“现在加载”图像,并在加载新数据后替换它。

Some code without a callback:

function grabAndFreeze() {
    showNowLoading(true);
    var jsondata = getData('http://yourserver.com/data/messages.json');
    /* User Interface 'freezes' while getting data */
    processData(jsondata);
    showNowLoading(false);
    do_other_stuff(); // not called until data fully downloaded
}

function processData(jsondata) { // do something with the data
   var count = jsondata.results ? jsondata.results.length : 0;
   $('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
   $('#results_messages').html(jsondata.results || '(no new messages)');
}

With Callback:

Here is an example with a callback, using jQuery's getJSON:

下面是一个使用jQuery getJSON的回调函数示例:

function processDataCB(jsondata) { // callback: update UI with results
   showNowLoading(false);
   var count = jsondata.results ? jsondata.results.length : 0;
   $('#counter_messages').text(['Fetched', count, 'new items'].join(' '));
   $('#results_messages').html(jsondata.results || '(no new messages)');
}

function grabAndGo() { // and don't freeze
    showNowLoading(true);
    $('#results_messages').html(now_loading_image);
    $.getJSON("http://yourserver.com/data/messages.json", processDataCB);
    /* Call processDataCB when data is downloaded, no frozen User Interface! */
    do_other_stuff(); // called immediately
}

With Closure:

Often the callback needs to access state from the calling function using a closure, which is like the Worker needing to get information from the Manager before he can complete his Task. To create the closure, you can inline the function so it sees the data in the calling context:

通常,回调需要使用闭包从调用函数访问状态,这就像工作人员在完成任务之前需要从管理器获取信息一样。要创建闭包,可以内联该函数,以便在调用上下文中看到数据:

/* Grab messages, chat users, etc by changing dtable. Run callback cb when done.*/
function grab(dtable, cb) { 
    if (null == dtable) { dtable = "messages"; }
    var uiElem = "_" + dtable;
    showNowLoading(true, dtable);
    $('#results' + uiElem).html(now_loading_image);
    $.getJSON("http://yourserver.com/user/"+dtable+".json", cb || function (jsondata) {
       // Using a closure: can "see" dtable argument and uiElem variables above.
       var count = jsondata.results ? jsondata.results.length : 0, 
           counterMsg = ['Fetched', count, 'new', dtable].join(' '),
           // no new chatters/messages/etc
           defaultResultsMsg = ['(no new ', dtable, ')'].join(''); 
       showNowLoading(false, dtable);
       $('#counter' + uiElem).text(counterMsg);
       $('#results'+ uiElem).html(jsondata.results || defaultResultsMsg);
    });
    /* User Interface calls cb when data is downloaded */

    do_other_stuff(); // called immediately
}

Usage:

// update results_chatters when chatters.json data is downloaded:
grab("chatters"); 
// update results_messages when messages.json data is downloaded
grab("messages"); 
// call myCallback(jsondata) when "history.json" data is loaded:
grab("history", myCallback); 

Closure

Finally, here is a definition of closure from Douglas Crockford:

最后,这是道格拉斯·克罗克福德的封闭性定义:

Functions can be defined inside of other functions. The inner function has access to the vars and parameters of the outer function. If a reference to an inner function survives (for example, as a callback function), the outer function's vars also survive.

函数可以在其他函数中定义。内部函数可以访问外部函数的vars和参数。如果引用一个内部函数(例如,作为一个回调函数),外部函数的vars也会存在。

See also:

参见:

#4


29  

I'm stunned to see so many intelligent people failing to stress the reality that the word "callback" has come to be used in two inconsistent ways.

看到这么多聪明的人没能强调“回调”这个词被用在两种不一致的方式上,我感到震惊。

Both ways involve the customization of a function by passing additional functionality (a function definition, anonymous or named) to an existing function. ie.

这两种方法都包括通过将附加功能(函数定义、匿名或命名)传递给现有函数来定制函数。ie。

customizableFunc(customFunctionality)

If the custom functionality is simply plugged into the code block, you have customized the function, like so.

如果定制的功能只是插入到代码块中,那么您已经定制了该函数,就像这样。

    customizableFucn(customFunctionality) {
      var data = doSomthing();
      customFunctionality(data);
      ...
    }

Though this kind of injected functionality is often called a "callback", there is nothing contingent about it. A very obvious example is the forEach method in which a custom function is supplied as an argument to be applied to each element in an array to modify the array.

尽管这种注入的功能通常被称为“回调”,但它并没有什么偶然的。一个非常明显的例子是forEach方法,它提供了一个自定义函数作为参数来应用于数组中的每个元素以修改数组。

But this is fundamentally distinct from the use of "callback" functions for asynchronous programming, as in AJAX or node.js or simply in assigning functionality to user interaction events (like mouse clicks). In this case, the whole idea is to wait for a contingent event to occur before executing the custom functionality. This is obvious in the case of user interaction, but is also important in i/o (input/output) processes that can take time, like reading files from disk. This is where the term "callback" makes the most obvious sense. Once an i/o process is started (like asking for a file to be read from disk or a server to return data from an http request) an asynchronous program doesn't wait around for it to finish. It can go ahead with whatever tasks are scheduled next, and only respond with the custom functionality after it has been notified that the read file or http request is completed (or that it failed) and that the data is available to the custom functionality. It's like calling a business on the phone and leaving your "callback" number, so they can call you when someone is available to get back to you. That's better than hanging on the line for who knows how long and not being able to attend to other affairs.

但这与异步编程(如AJAX或node)中的“回调”函数的使用截然不同。js或简单地将功能分配给用户交互事件(如鼠标点击)。在这种情况下,整个想法是在执行定制功能之前等待一个偶然事件发生。在用户交互的情况下,这一点很明显,但是在输入/输出过程中也很重要,这需要时间,就像从磁盘读取文件一样。这就是“回调”一词最明显的意义所在。一旦启动了i/o进程(比如请求从磁盘读取文件或服务器从http请求返回数据),异步程序就不会等待它完成。它可以继续执行下一项任务,并且只在被通知读取文件或http请求完成(或者它失败了)和数据对自定义功能可用之后才响应定制的功能。这就像打电话给一个公司,留下你的“回调”号码,这样他们就可以在有人回来找你的时候给你打电话。这总比挂在电话上好,因为谁知道有多少时间不能处理其他事情。

Asynchronous use inherently involves some means of listening for the desired event (e.g, the completion of the i/o process) so that, when it occurs (and only when it occurs) the custom "callback" functionality is executed. In the obvious AJAX example, when the data actually arrives from the server, the "callback" function is triggered to use that data to modify the DOM and therefore redraw the browser window to that extent.

异步使用本身包含了一些侦听所需事件的方法(e)。i/o进程的完成,当它发生时(并且只有当它发生时),定制的“回调”功能才会被执行。在明显的AJAX示例中,当数据实际来自服务器时,“回调”函数被触发,以使用该数据修改DOM,从而在此范围内重新绘制浏览器窗口。

To recap. Some people use the word "callback" to refer to any kind of custom functionality that can be injected into an existing function as an argument. But, at least to me, the most appropriate use of the word is where the injected "callback" function is used asynchronously -- to be executed only upon the occurrence of an event that it is waiting to be notified of.

回顾一下。有些人使用“回调”这个词来指代任何一种自定义功能,这些功能可以被注入到现有函数中作为参数。但是,至少对我来说,最恰当地使用这个词的地方是,注入的“回调”函数被异步地使用——只在它等待被通知的事件发生时被执行。

#5


25  

In non-programmer terms, a callback is a fill-in-the-blank in a program.

在非程序员术语中,回调是程序中的填空。

A common item on many paper forms is "Person to call in case of emergency". There is a blank line there. You write in someone's name and phone number. If an emergency occurs, then that person gets called.

许多纸质表格上的一个常见项目是“紧急情况下打电话的人”。这里有一条空行。你用别人的名字和电话来写。如果发生紧急情况,那么这个人就会被呼叫。

  • Everyone gets the same blank form, but
  • 每个人都有相同的空白表格,但是。
  • Everyone can write a different emergency contact number.
  • 每个人都可以写一个不同的紧急联系电话。

This is key. You do not change the form (the code, usually someone else's). However you can fill in missing pieces of information (your number).

这是关键。您不会更改表单(代码,通常是其他人的)。然而,你可以填写丢失的信息(你的号码)。

Example 1:

示例1:

Callbacks are used as customized methods, possibly for adding to/changing a program's behavior. For example, take some C code that performs a function, but does not know how to print output. All it can do is make a string. When it tries to figure out what to do with the string, it sees a blank line. But, the programmer gave you the blank to write your callback in!

回调被用作定制的方法,可能是为了增加/改变一个程序的行为。例如,使用一些执行函数的C代码,但不知道如何打印输出。它所能做的就是做一个字符串。当它试图弄清楚如何处理字符串时,它会看到一个空行。但是,程序员给了你空白写回你的回叫!

In this example, you do not use a pencil to fill in a blank on a sheet of paper, you use the function set_print_callback(the_callback).

在本例中,您不用铅笔在一张纸上填写空白,您可以使用函数set_print_callback(the_callback)。

  • The blank variable in the module/code is the blank line,
  • 模块/代码中的空白变量为空行,
  • set_print_callback is the pencil,
  • set_print_callback是铅笔,
  • and the_callback is your information you are filling in.
  • 而the_callback是你填写的信息。

You've now filled in this blank line in the program. Whenever it needs to print output, it will look at that blank line, and follow the instructions there (i.e. call the function you put there.) Practically, this allows the possibility of printing to screen, to a log file, to a printer, over a network connection, or any combination thereof. You have filled in the blank with what you want to do.

您现在已经在程序中填充了这个空行。当它需要打印输出时,它会查看那个空行,并按照那里的指令(即调用你放在那里的函数)。实际上,这允许打印屏幕、日志文件、打印机、网络连接或其任何组合的可能性。你已经填满了你想做的事。

Example 2:

示例2:

When you get told you need to call an emergency number, you go and read what is written on the paper form, and then call the number you read. If that line is blank nothing will be done.

当你被告知需要拨打一个紧急电话号码时,你可以去读一下纸上写的内容,然后拨打你所读的电话号码。如果这条线是空的,什么也不会做。

Gui programming works much the same way. When a button is clicked, the program needs to figure out what to do next. It goes and looks for the callback. This callback happens to be in a blank labeled "Here's what you do when Button1 is clicked"

Gui编程的工作方式也大致相同。当一个按钮被点击,程序需要知道下一步该做什么。它去寻找回调函数。这个回调恰好是在一个空白的标签中"这是当Button1被点击时你所做的"

Most IDEs will automatically fill in the blank for you (write the basic method) when you ask it to (e.g. button1_clicked). However that blank can have any method you darn well please. You could call the method run_computations or butter_the_biscuits as long as you put that callback's name in the proper blank. You could put "555-555-1212" in the emergency number blank. It doesn't make much sense, but it's permissible.

大多数ide会在你要求它(例如button1_click)的时候自动填充你的空白(写基本的方法)。但是,这个空白可以有任何方法,请。只要将回调的名称放在适当的空白中,就可以调用方法run_compution或butter_the_biscuits。你可以把“555-555-1212”放在紧急号码栏里。这没有多大意义,但这是允许的。


Final note: That blank line that you're filling in with the callback? It can be erased and re-written at will. (whether you should or not is another question, but that is a part of their power)

最后注意:你填入回调的那个空行?它可以被删除和重写。(不管你是否应该,这是另一个问题,但这是他们力量的一部分)

#6


20  

Johny the programmer needs a stapler, so he goes down to the office supply department and ask for one, after filling the request form he can either stand there and wait for the clerk go look around the warehouse for the stapler (like a blocking function call) or go do something else meantime.

约翰尼程序员需要一个订书机,所以他走到办公用品部门要求,填写申请表后,他可以站在那里,等待订书机的职员去看看仓库(如阻塞函数调用)或去做别的事情。

since this usually takes time, johny puts a note together with the request form asking them to call him when the stapler is ready for pickup, so meantime he can go do something else like napping on his desk.

因为这通常需要时间,johny把一张纸条和请求表格一起,让他们在订书机准备好了的时候给他打电话,这样他就可以去做一些其他的事情,比如在他的桌子上打盹。

#7


19  

Always better to start with an example :).

最好从一个例子开始:)。

Let's assume you have two modules A and B.

假设你有两个模块A和B。

You want module A to be notified when some event/condition occurs in module B. However, module B has no idea about your module A. All it knows is an address to a particular function (of module A) through a function pointer that is provided to it by module A.

您希望模块A在某些事件/条件发生时得到通知。但是,模块B不知道您的模块A。它所知道的是通过一个由模块A提供给它的函数指针对特定函数(模块A)的一个地址。

So all B has to do now, is "callback" into module A when a particular event/condition occurs by using the function pointer. A can do further processing inside the callback function.

所以B现在必须做的是,当一个特定的事件/条件通过函数指针发生时,“回调”到模块A中。可以在回调函数中进行进一步的处理。

*) A clear advantage here is that you are abstracting out everything about module A from module B. Module B does not have to care who/what module A is.

这里有一个明显的优点,就是你可以从模块B中抽象出所有关于模块A的内容。B模块不需要关心A模块是什么。

#8


16  

Imagine you need a function that returns 10 squared so you write a function:

假设你需要一个函数返回10的平方所以你写一个函数

function tenSquared() {return 10*10;}

Later you need 9 squared so you write another function:

之后你需要9的平方所以你写另一个函数

function nineSquared() {return 9*9;}

Eventually you will replace all of these with a generic function:

最终你会用一个通用的函数来替换所有这些:

function square(x) {return x*x;}

The exact same thinking applies for callbacks. You have a function that does something and when done calls doA:

同样的想法也适用于回调。你有一个函数,它做了一些事情,当完成调用doA:

function computeA(){
    ...
    doA(result);
}

Later you want the exact same function to call doB instead you could duplicate the whole function:

稍后,你需要完全相同的函数调用doB,你可以复制整个函数:

function computeB(){
    ...
    doB(result);
}

Or you could pass a callback function as a variable and only have to have the function once:

或者可以将回调函数作为变量传递,只需要有一次函数:

function compute(callback){
    ...
    callback(result);
}

Then you just have to call compute(doA) and compute(doB).

然后只需调用compute(doA)和compute(doB)。

Beyond simplifying code, it lets asynchronous code let you know it has completed by calling your arbitrary function on completion, similar to when you call someone on the phone and leave a callback number.

除了简化代码之外,它还允许异步代码通过在完成时调用您的任意函数来完成,类似于您在电话中调用某人并留下一个回调号。

#9


10  

You feel ill so you go to the doctor. He examines you and determines you need some medication. He prescribes some meds and calls the prescription into your local pharmacy. You go home. Later your pharmacy calls to tell you your prescription is ready. You go and pick it up.

你觉得不舒服,就去看医生。他检查你,确定你需要一些药物。他开了一些药,并把处方开到你当地的药房。你回家了。后来你的药店打电话告诉你你的处方已经准备好了。你去把它捡起来。

#10


9  

There's two points to explain, one is how a callback works (passing around a function that can be called without any knowledge of its context), the other what it's used for (handling events asynchronously).

有两点需要解释,一个是回调是如何工作的(传递一个可以在不了解其上下文的情况下调用的函数),另一个是它的用途(异步处理事件)。

The analogy of waiting for a parcel to arrive that has been used by other answers is a good one to explain both. In a computer program, you would tell the computer to expect a parcel. Ordinarily, it would now sit there and wait (and do nothing else) until the parcel arrives, possibly indefinitely if it never arrives. To humans, this sounds silly, but without further measures, this is totally natural to a computer.

等待一个包裹到达的类比,已经被其他答案所使用,这是一个很好的解释。在电脑程序中,你会告诉电脑要寄包裹。通常情况下,它会一直呆在那里等待,直到包裹到达,如果它永远不会到达的话,可能是无限期的。对人类来说,这听起来很傻,但如果没有进一步的措施,这对计算机来说是完全自然的。

Now the callback would be the bell at your front door. You provide the parcel service with a way to notify you of the parcel's arrival without them having to know where (even if) you are in the house, or how the bell works. (For instance, some "bells" actually dispatch a phone call.) Because you provided a "callback function" that can be "called" at any time, out of context, you can now stop sitting at the front porch and "handle the event" (of parcel arrival) whenever it's time.

现在回调就是你家前门的门铃了。你提供包裹服务的方式是通知你包裹的到达,而不需要他们知道你在哪里(即使你在房子里),或者门铃是如何工作的。(例如,一些“铃声”实际上是在发送一个电话。)因为您提供了一个“回调函数”,可以在任何时候被“调用”,在上下文之外,您现在可以停止坐在前门廊和“处理事件”(包裹到达)的时间。

#11


6  

Imagine a friend is leaving your house, and you tell her "Call me when you get home so that I know you arrived safely"; that is (literally) a call back. That's what a callback function is, regardless of language. You want some procedure to pass control back to you when it has completed some task, so you give it a function to use to call back to you.

想象一个朋友离开你的家,你告诉她“回家后给我打电话,这样我就知道你安全到达了”;这是(字面上的)回调。这就是回调函数,不管语言是什么。当它完成了一些任务时,您需要一些过程来将控制权传递给您,因此您给它一个函数来调用返回给您。

In Python, for example,

在Python中,例如,

grabDBValue( (lambda x: passValueToGUIWindow(x) ))

grabDBValue could be written to only grab a value from a database and then let you specify what to actually do with the value, so it accepts a function. You don't know when or if grabDBValue will return, but if/when it does, you know what you want it to do. Here, I pass in an anonymous function (or lambda) that sends the value to a GUI window. I could easily change the behavior of the program by doing this:

可以编写grabDBValue来从数据库中获取一个值,然后让您指定如何处理该值,因此它接受一个函数。您不知道何时或如果grabDBValue将返回,但是如果/当它发生时,您知道您想要它做什么。这里,我传入一个匿名函数(或lambda),该函数将值发送到GUI窗口。我可以很容易地改变程序的行为:

grabDBValue( (lambda x: passToLogger(x) ))

Callbacks work well in languages where functions are first class values, just like the usual integers, character strings, booleans, etc. In C, you can "pass" a function around by passing around a pointer to it and the caller can use that; in Java, the caller will ask for a static class of a certain type with a certain method name since there are no functions ("methods," really) outside of classes; and in most other dynamic languages you can just pass a function with simple syntax.

回调函数在函数为一级值的语言中工作得很好,就像通常的整数、字符字符串、布尔值等等。在C中,通过传递一个指针来传递函数,调用者可以使用它;在Java中,调用者将要求具有特定方法名称的特定类型的静态类,因为在类之外没有函数(“方法”,真的);在大多数其他的动态语言中,你可以通过简单的语法传递函数。

Protip:

In languages with lexical scoping (like Scheme or Perl) you can pull a trick like this:

在使用词汇范围(如Scheme或Perl)的语言中,您可以使用如下方法:

my $var = 2;
my $val = someCallerBackFunction(sub callback { return $var * 3; });
# Perlistas note: I know the sub doesn't need a name, this is for illustration

$val in this case will be 6 because the callback has access to the variables declared in the lexical environment where it was defined. Lexical scope and anonymous callbacks are a powerful combination warranting further study for the novice programmer.

在此情况下,$val将是6,因为回调可以访问定义它的词汇环境中声明的变量。词汇范围和匿名回调是对初学者进行进一步研究的有力组合。

#12


6  

You have some code you want to run. Normally, when you call it you are then waiting for it to be finished before you carry on (which can cause your app to go grey/produce a spinning time for a cursor).

你有一些你想要运行的代码。通常,当你调用它的时候,你会等待它在你继续之前完成(这可能会导致你的应用程序变灰/为光标产生旋转时间)。

An alternative method is to run this code in parallel and carry on with your own work. But what if your original code needs to do different things depending on the response from the code it called? Well, in that case you can pass in the name/location of the code you want it to call when it's done. This is a "call back".

另一种方法是并行运行此代码,并继续您自己的工作。但是,如果您的原始代码需要根据它所调用的代码的响应来做不同的事情呢?那么,在这种情况下,您可以传递您希望它在完成时调用的代码的名称/位置。这是“回电”。

Normal code: Ask for Information->Process Information->Deal with results of Processing->Continue to do other things.

正常代码:要求信息->过程信息->处理结果->继续做其他事情。

With callbacks: Ask for Information->Process Information->Continue to do other things. And at some later point->Deal with results of Processing.

使用回调:请求信息->过程信息->继续做其他事情。在后来的一些时候,>处理了处理结果。

#13


6  

Without callback neither others special programming resources (like threading, and others), a program is exactly a sequence of instructions which are executed sequentially one after the other, and even with a kind of "dynamic behavior" determined by certain conditions, all possible scenarios shall be previously programmed.

如果没有回调其他的特殊编程资源(如线程和其他),程序就是按顺序依次执行的指令序列,即使是在某些条件下确定的“动态行为”,所有可能的场景都应该预先编程。

So, If we need to provide a real dynamic behavior to a program we can use callback. With callback you can instructs by parameters, a program to call an another program providing some previously defined parameters and can expects some results (this is the contract or operation signature), so these results can be produced/processed by third-party program which wasn't previously known.

因此,如果我们需要为程序提供一个真正的动态行为,我们可以使用回调。有了回调,您可以通过参数指示一个程序,该程序可以调用另一个程序,提供一些以前定义的参数,并且可以预期一些结果(这是合同或操作签名),因此这些结果可以由以前不知道的第三方程序生成/处理。

This technique is the foundation of polymorphism applied to programs, functions, objects and all others unities of code ran by computers.

该技术是应用于程序、函数、对象和所有其他由计算机运行的代码统一的多态性的基础。

The human world used as example to callback is nice explained when you are doing some job, lets suppose you are a painter (here you are the main program, that paints) and call your client sometimes to ask him to approve the result of your job, so, he decides if the picture is good (your client is the third-party program).

人类世界作为例子来调很好解释,当你做一些工作,让我们假设你是一个画家(描绘)你是主程序,有时打电话给你的客户,请他批准你的工作的结果,所以,他决定如果这张照片是好的(客户是第三方程序)。

In the above example you are a painter and "delegate" to others the job to approve the result, the picture is the parameter, and each new client (the called-back "function") changes the result of your work deciding what he wants about the picture (the decision made by the clients are the returned result from the "callback function").

在上面的例子中你是一个画家,“委托”给别人工作批准结果,图片是参数,每个新客户(召回“函数”)改变你的工作的结果决定他想要什么图片(由客户决定从"回调函数")返回的结果。

I hope this explanation can be useful.

我希望这个解释是有用的。

#14


6  

Let's pretend you were to give me a potentially long-running task: get the names of the first five unique people you come across. This might take days if I'm in a sparsely populated area. You're not really interested in sitting on your hands while I'm running around so you say, "When you've got the list, call me on my cell and read it back to me. Here's the number.".

让我们假设你给了我一个潜在的长期任务:获取你遇到的前五个独特的人的名字。如果我在人烟稀少的地区,这可能需要几天的时间。当我跑来跑去的时候,你对坐在你的手上不感兴趣,所以你说:“当你拿到清单的时候,打电话给我,把它读给我听。”这是数字。”。

You've given me a callback reference--a function that I'm supposed to execute in order to hand off further processing.

您已经给了我一个回调引用——一个我应该执行的函数,以便进行进一步的处理。

In JavaScript it might look something like this:

在JavaScript中,它可能是这样的:

var lottoNumbers = [];
var callback = function(theNames) {
  for (var i=0; i<theNames.length; i++) {
    lottoNumbers.push(theNames[i].length);
  }
};

db.executeQuery("SELECT name " +
                "FROM tblEveryOneInTheWholeWorld " +
                "ORDER BY proximity DESC " +
                "LIMIT 5", callback);

while (lottoNumbers.length < 5) {
  playGolf();
}
playLotto(lottoNumbers);

This could probably be improved in lots of ways. E.g., you could provide a second callback: if it ends up taking longer than an hour, call the red phone and tell the person that answers that you've timed out.

这可能会在很多方面得到改善。例如,你可以提供第二个回叫:如果它结束的时间超过一个小时,打电话给那个人,告诉他你超时了。

#15


5  

A callback is a function that will be called by a second function. This second function doesn't know in advance what function it will call. So the identity of the callback function is stored somewhere, or passed to the second function as a parameter. This "identity," depending on the programming language, might be the address of the callback, or some other sort of pointer, or it might be the name of the function. The principal is the same, we store or pass some information that unambiguously identifies the function.

回调函数是由第二个函数调用的函数。第二个函数不知道它会调用什么函数。因此,回调函数的标识存储在某个地方,或者作为参数传递给第二个函数。这个“标识”,取决于编程语言,可能是回调的地址,或者其他类型的指针,或者它可能是函数的名称。主体是相同的,我们存储或传递一些明确标识函数的信息。

When the time comes, the second function can call the callback, supplying parameters depending on the circumstances at that moment. It might even choose the callback from a set of possible callbacks. The programming language must provide some kind of syntax to allow the second function to call the callback, knowing its "identity."

当时间到来时,第二个函数可以调用回调,根据当时的情况提供参数。它甚至可能从一组可能的回调中选择回调。编程语言必须提供某种语法,以允许第二个函数调用回调函数,知道它的“身份”。

This mechanism has a great many possible uses. With callbacks, the designer of a function can let it be customized by having it call whatever callbacks are provided. For example, a sorting function might take a callback as a parameter, and this callback might be a function for comparing two elements to decide which one comes first.

这种机制有许多可能的用途。通过回调,函数的设计器可以让它通过调用所提供的任何回调来定制。例如,排序函数可能将回调作为参数,而这个回调可能是比较两个元素的函数,以决定哪一个元素先出现。

By the way, depending on the programming language, the word "function" in the above discussion might be replaced by "block," "closure," "lambda," etc.

顺便说一下,根据编程语言,上面讨论中的“函数”一词可能会被“block”、“闭包”、“lambda”等取代。

#16


5  

Callbacks are most easily described in terms of the telephone system. A function call is analogous to calling someone on a telephone, asking her a question, getting an answer, and hanging up; adding a callback changes the analogy so that after asking her a question, you also give her your name and number so she can call you back with the answer. -- Paul Jakubik , "Callback Implementations in C++"

在电话系统中最容易描述回调。一个函数调用类似于打电话给某人,问她一个问题,得到一个答案,然后挂断电话;添加一个回调会改变这个类比,这样在问了她一个问题之后,你也可以告诉她你的名字和号码,这样她就可以给你回电话了。——Paul Jakubik,“c++中的回调实现”

#17


5  

Usually we sent variables to functions . Suppose you have task where the variable needs to be processed before being given as an argument - you can use callback .

通常我们把变量发送给函数。假设您有任务,在将变量作为参数给定之前,需要处理变量——您可以使用回调。

function1(var1, var2) is the usual way .

函数1(var1, var2)是通常的方法。

What if I want var2 to be processed and then sent as an argument? function1(var1, function2(var2))

如果我想要处理var2,然后作为参数发送呢?function1(var1 function2(var2))

This is one type of callback - where function2 executes some code and returns a variable back to the initial function .

这是一种回调函数——function2执行一些代码并将变量返回到初始函数。

#18


4  

A metaphorical explanation:

一个隐喻的解释:

I have a parcel I want delivered to a friend, and I also want to know when my friend receives it.

我有一个包裹要寄给一个朋友,我也想知道我的朋友什么时候收到的。

So I take the parcel to the post office and ask them to deliver it. If I want to know when my friend receives the parcel, I have two options:

所以我把包裹送到邮局,让他们送去。如果我想知道我的朋友什么时候收到包裹,我有两个选择:

(a) I can wait at the post office until it is delivered.

(a)我可以在邮局等候,直到收到为止。

(b) I will get an email when it is delivered.

(b)发送邮件时,我将收到一封邮件。

Option (b) is analogous to a callback.

选项(b)类似于回调。

#19


4  

For teaching callbacks, you have to teach the pointer first. Once the students understand the idea of pointer to a variable, idea of callbacks will get easier. Assuming you are using C/C++, these steps can be followed.

要教回调,你必须先教指针。一旦学生理解了指向变量的指针,回调的概念就会变得更容易。假设您使用的是C/ c++,可以遵循以下步骤。

  • First show your students how to use and manipulate variables using pointers alongside using the normal variable identifiers.
  • 首先向您的学生展示如何使用和操作使用指针的变量,以及使用常规变量标识符。
  • Then teach them there are things that can be done only with pointers(like passing a variable by reference).
  • 然后告诉他们,有些事情只能用指针来完成(比如通过引用传递变量)。
  • Then tell them how executable code or functions are just like some other data(or variables) in the memory. So, functions also have addresses or pointers.
  • 然后告诉他们可执行代码或函数与内存中的其他数据(或变量)是一样的。函数也有地址或指针。
  • Then show them how functions can be called with function pointers and tell these are called callbacks.
  • 然后向他们展示如何用函数指针调用函数,并告诉这些函数称为回调函数。
  • Now, the question is, why all these hassle for calling some functions? What is the benefit? Like data pointers, function pointer aka callbacks has some advantages over using normal identifiers.
  • 现在的问题是,为什么要调用一些函数呢?好处是什么?与数据指针一样,函数指针又名回调比使用普通标识符有一些优势。
  • The first one is, function identifiers or function names cannot be used as normal data. I mean, you cannot make a data structure with functions(like an array or a linked list of functions). But with callbacks, you can make an array, a linked list or use them with other data like in dictionary of key-value pairs or trees, or any other things. This is a powerful benefit. And other benefits are actually child of this one.
  • 第一个是,函数标识符或函数名不能用作正常数据。我的意思是,你不能用函数来构造一个数据结构(比如数组或函数链表)。但是有了回调,您可以创建一个数组,一个链表,或者在键值对、树或其他任何东西的字典中使用它们。这是一个强大的好处。其他的好处实际上是这个的孩子。
  • The most common use of callbacks is seen in event driver programming. Where one or more functions are executed based on some incoming signal. With callbacks, a dictionary can be maintained to map signals with callbacks. Then the input signal resolution and execution of corresponding code become much easier.
  • 最常见的回调使用是在事件驱动程序编程中。其中一个或多个函数是基于某个传入信号执行的。有了回调,就可以维护一个字典来映射带有回调的信号。然后,输入信号的分辨率和相应代码的执行变得容易得多。
  • The second use of callbacks coming in my mind is higher order functions. The functions which takes other functions as input arguments. And to send functions as arguments, we need callbacks. An example can be a function which take an array and a callback. Then it performs the callback on each of the item of the array and return the results in another array. If we pass the function a doubling callback, we get a doubled valued array. If we pass a squaring callback, we get squares. For square roots, just send appropriate callback. This cannot be done with normal functions.
  • 在我脑海中第二次使用回调函数是高阶函数。将其他函数作为输入参数的函数。要发送函数作为参数,我们需要回调。一个示例可以是一个带数组和回调的函数。然后,它在数组的每个项上执行回调,并将结果返回到另一个数组中。如果我们传递函数一个加倍回调,我们得到一个加倍值的数组。如果我们通过平方回调,就会得到平方。对于平方根,只需发送适当的回调。这不能用正常的函数来完成。

There might many more things. Involve the students and they will discover. Hope this helps.

可能还有更多的东西。让学生参与,他们会发现。希望这个有帮助。

#20


3  

In plain english a callback is a promise. Joe, Jane, David and Samantha share a carpool to work. Joe is driving today. Jane, David and Samantha have a couple of options:

在普通英语中,回调是一个承诺。乔、简、大卫和萨曼莎共用一个拼车。乔今天开车。Jane, David和Samantha有几个选择:

  1. Check the window every 5 minutes to see if Joe is out
  2. 每隔5分钟检查一下窗户,看看乔是否出去了。
  3. Keep doing their thing until Joe rings the door bell.
  4. 继续做他们的事,直到乔按门铃。

Option 1: This is more like a polling example where Jane would be stuck in a "loop" checking if Joe is outside. Jane can't do anything else in the mean time.

选项1:这更像是一个轮询示例,在这个例子中,Jane将被困在一个“循环”中,检查Joe是否在外面。简不能在平时做别的事情。

Option 2: This is the callback example. Jane tells Joe to ring her doorbell when he's outside. She gives him a "function" to ring the door bell. Joe does not need to know how the door bell works or where it is, he just needs to call that function i.e. ring the door bell when he's there.

选项2:这是回调示例。简告诉乔在他外出时按响她的门铃。她给了他一个按门铃的“功能”。乔不需要知道门铃是怎么工作的,也不需要知道它在哪里,他只需要调用那个功能,即当他在那里时按门铃。

Callbacks are driven by "events". In this example the "event" is Joe's arrival. In Ajax for example events can be "success" or "failure" of the asynchronous request and each can have the same or different callbacks.

回调是由“事件”驱动的。在这个例子中,“事件”是Joe的到达。在Ajax中,事件可以是异步请求的“成功”或“失败”,每个都可以有相同或不同的回调。

In terms of JavaScript applications and callbacks. We also need to understand "closures" and application context. What "this" refers to can easily confuse JavaScript developers. In this example within each person's "ring_the_door_bell()" method/callback there might be some other methods that each person need to do based on their morning routine ex. "turn_off_the_tv()". We would want "this" to refer to the "Jane" object or the "David" object so that each can setup whatever else they need done before Joe picks them up. This is where setting up the callback with Joe requires parodying the method so that "this" refers to the right object.

就JavaScript应用程序和回调而言。我们还需要理解“闭包”和应用程序上下文。“this”指的是容易让JavaScript开发人员迷惑的东西。在这个示例中,每个人的“ring_the_door_bell()”方法/回调中可能会有一些其他的方法,每个人都需要根据他们的早晨例程来做。“turn_off_the_tv()”。我们希望“this”指的是“Jane”对象或“David”对象,这样每个人都可以在Joe接他们之前安装他们需要的任何其他东西。在这里,与Joe一起设置回调需要对方法进行解析,以便“This”指的是正确的对象。

Hope that helps!

希望会有帮助!

#21


3  

A callback is a self-addressed stamped envelope. When you call a function, that is like sending a letter. If you want that function to call another function you provide that information in the form of a reference or address.

回调是一个自寻地址的邮票信封。当你调用一个函数时,这就像发送一个字母。如果您希望该函数调用另一个函数,则以引用或地址的形式提供该信息。

#22


3  

What Is a Callback Function?

什么是回调函数?

The simple answer to this first question is that a callback function is a function that is called through a function pointer. If you pass the pointer (address) of a function as an argument to another, when that pointer is used to call the function it points to it is said that a call back is made.

第一个问题的简单答案是,回调函数是通过函数指针调用的函数。如果将一个函数的指针(地址)传递给另一个函数,当该指针被用来调用该函数时,它指向的函数是返回的函数。

Callback function is hard to trace, but sometimes it is very useful. Especially when you are designing libraries. Callback function is like asking your user to gives you a function name, and you will call that function under certain condition.

回调函数很难跟踪,但有时它非常有用。特别是当你在设计图书馆的时候。回调函数就像让用户给你一个函数名,你会在一定条件下调用这个函数。

For example, you write a callback timer. It allows you to specified the duration and what function to call, and the function will be callback accordingly. “Run myfunction() every 10 seconds for 5 times”

例如,编写一个回调计时器。它允许您指定要调用的时间和函数,并且该函数将相应地回调。“每10秒运行myfunction() 5次”

Or you can create a function directory, passing a list of function name and ask the library to callback accordingly. “Callback success() if success, callback fail() if failed.”

或者,您可以创建一个函数目录,传递函数名列表,并要求库相应地回调。“回调成功()如果成功,回调失败()如果失败。”

Lets look at a simple function pointer example

让我们来看一个简单的函数指针示例。

void cbfunc()
{
     printf("called");
}

 int main ()
 {
                   /* function pointer */ 
      void (*callback)(void); 
                   /* point to your callback function */ 
      callback=(void *)cbfunc; 
                   /* perform callback */
      callback();
      return 0; 
}

How to pass argument to callback function?

如何将参数传递给回调函数?

Observered that function pointer to implement callback takes in void *, which indicates that it can takes in any type of variable including structure. Therefore you can pass in multiple arguments by structure.

Observered函数指针在void *中执行回调,这表明它可以接收任何类型的变量,包括结构。因此,您可以通过结构传递多个参数。

typedef struct myst
{
     int a;
     char b[10];
}myst;

void cbfunc(myst *mt) 
{
     fprintf(stdout,"called %d %s.",mt->a,mt->b); 
}

int main() 
{
       /* func pointer */
    void (*callback)(void *);       //param
     myst m;
     m.a=10;
     strcpy(m.b,"123");       
     callback = (void*)cbfunc;    /* point to callback function */
     callback(&m);                /* perform callback and pass in the param */
     return 0;   
}

#23


2  

A callback is a method that is scheduled to be executed when a condition is met.

回调是在满足条件时被调度执行的方法。

An "real world" example is a local video game store. You are waiting for Half-Life 3. Instead of going to the store every day to see if it is in, you register your email on a list to be notified when the game is available. The email becomes your "callback" and the condition to be met is the game's availability.

一个“真实世界”的例子是一个本地的视频游戏商店。你在等半辈子。与其每天去商店看看它是否在,你在一个名单上登记你的电子邮件,当游戏是可用的时候通知。电子邮件成为你的“回调”,满足的条件是游戏的可用性。

A "programmers" example is a web page where you want to perform an action when a button is clicked. You register a callback method for a button and continue doing other tasks. When/if the user cicks on the button, the browser will look at the list of callbacks for that event and call your method.

“程序员”示例是一个web页面,您希望在单击按钮时执行操作。您为一个按钮注册一个回调方法,并继续执行其他任务。当/如果用户在按钮上有cicks,浏览器将查看该事件的回调列表并调用您的方法。

A callback is a way to handle events asynchronously. You can never know when the callback will be executed, or if it will be executed at all. The advantage is that it frees your program and CPU cycles to perform other tasks while waiting for the reply.

回调是一种异步处理事件的方法。您永远不知道什么时候会执行回调,或者它是否会被执行。它的优点是可以在等待应答时释放程序和CPU周期来执行其他任务。

#24


2  

Plain and simple: A callback is a function that you give to another function, so that it can call it.

简单和简单:回调函数是您赋予另一个函数的函数,因此它可以调用它。

Usually it is called when some operation is completed. Since you create the callback before giving it to the other function, you can initialize it with context information from the call site. That is why it is named a call*back* - the first function calls back into the context from where it was called.

通常在某些操作完成时调用。由于在将回调函数赋给另一个函数之前创建了回调函数,因此可以从调用站点的上下文信息初始化它。这就是为什么它被命名为call*back*——第一个函数调用从它被调用的地方返回的上下文。

#25


2  

I think it's an rather easy task to explain.

我认为这是一个相当容易解释的任务。

At first callback are just ordinary functions.
And the further is, that we call this function (let's call it A) from inside another function (let's call it B).

第一次回调只是普通的函数。更进一步,我们把这个函数(我们称之为A)从另一个函数中调用(我们叫它B)

The magic about this is that I decide, which function should be called by the function from outside B.

关于这一点的神奇之处在于,我决定,函数应该由外部B的函数来调用。

At the time I write the function B I don't know which callback function should be called. At the time I call function B I also tell this function to call function A. That is all.

在编写函数B时,我不知道应该调用哪个回调函数。在我调用函数B的时候,我也告诉这个函数调用函数a,这就是全部。

#26


2  

“In computer programming, a callback is a reference to executable code, or a piece of executable code, that is passed as an argument to other code. This allows a lower-level software layer to call a subroutine (or function) defined in a higher-level layer.” - Wikipedia

在计算机编程中,回调是对可执行代码或可执行代码的引用,作为对其他代码的参数传递。这使得底层的软件层可以调用在高级层中定义的子程序(或函数)。”——*

Callback in C using Function Pointer

使用函数指针在C中回调。

In C, callback is implemented using Function Pointer. Function Pointer - as the name suggests, is a pointer to a function.

在C中,回调是使用函数指针实现的。函数指针——顾名思义,是指向函数的指针。

For example, int (*ptrFunc) ();

例如,int (*ptrFunc) ();

Here, ptrFunc is a pointer to a function that takes no arguments and returns an integer. DO NOT forget to put in the parenthesis, otherwise the compiler will assume that ptrFunc is a normal function name, which takes nothing and returns a pointer to an integer.

这里,ptrFunc是一个指向函数的指针,该函数不接受参数并返回整数。不要忘记插入括号,否则编译器会假设ptrFunc是一个正常的函数名,它不带任何东西,并返回一个指向整数的指针。

Here is some code to demonstrate the function pointer.

下面是演示函数指针的代码。

#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;
}

Now let us try to understand the concept of Callback in C using function pointer.

现在让我们试着用函数指针来理解回调函数的概念。

The complete program has three files: callback.c, reg_callback.h and reg_callback.c.

完整的程序有三个文件:回调。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)();                               
}

If we run this program, the output will be

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

This is a program demonstrating function callback inside register_callback inside my_callback back inside main program

这是一个在主程序内的my_callback内部的register_callback内演示函数回调的程序。

The higher layer function calls a lower layer function as a normal call and the callback mechanism allows the lower layer function to call the higher layer function through a pointer to a callback function.

上层函数调用底层函数作为普通调用,而回调机制允许底层函数通过指向回调函数的指针调用更高的层函数。

Callback in Java Using Interface

在Java中使用接口回调。

Java does not have the concept of function pointer It implements Callback mechanism through its Interface mechanism Here instead of a function pointer, we declare an Interface having a method which will be called when the callee finishes its task

Java没有函数指针的概念,它通过它的接口机制来实现回调机制,而不是一个函数指针,我们声明一个接口有一个方法,当callee完成它的任务时,它将被调用。

Let me demonstrate it through an example:

让我通过一个例子来证明:

The Callback Interface

回调接口

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

The Caller or the Higher Level Class

调用者或高级类。

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
}
}

The Callee or the lower layer function

Callee或下层的函数。

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 Using EventListener pattern

回调使用EventListener模式

  • List item
  • 列表项

This pattern is used to notify 0 to n numbers of Observers/Listeners that a particular task has finished

此模式用于将特定任务已完成的观察者/侦听器通知0到n。

  • List item
  • 列表项

The difference between Callback mechanism and EventListener/Observer mechanism is that in callback, the callee notifies the single caller, whereas in Eventlisener/Observer, the callee can notify anyone who is interested in that event (the notification may go to some other parts of the application which has not triggered the task)

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

Let me explain it through an example.

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

The Event Interface

事件接口

public interface Events {

public void clickEvent();
public void longClickEvent();
}

Class Widget

类部件

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);
    }
}

Class Button

类按钮

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

Class 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;
}
}

Activity Class

Activity类

package com.som_itsolutions.training.java.exampleeventlistener;

包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();
    }   
}

Other Class

其他类

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...");
}
}

Main Class

主类

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);
}
}

As you can see from the above code, that we have an interface called events which basically lists all the events that may happen for our application. The Widget class is the base class for all the UI components like Button, Checkbox. These UI components are the objects that actually receive the events from the framework code. Widget class implements the Events interface and also it has two nested interfaces namely OnClickEventListener & OnLongClickEventListener

正如您从上面的代码中看到的,我们有一个名为events的接口,它基本上列出了应用程序可能发生的所有事件。小部件类是所有UI组件(如按钮、复选框)的基类。这些UI组件是实际从框架代码接收事件的对象。Widget类实现了事件接口,并且它有两个嵌套的接口,即OnClickEventListener和OnLongClickEventListener。

These two interfaces are responsible for listening to events that may occur on the Widget derived UI components like Button or Checkbox. So if we compare this example with the earlier Callback example using Java Interface, these two interfaces work as the Callback interface. So the higher level code (Here Activity) implements these two interfaces. And whenever an event occurs to a widget, the higher level code (or the method of these interfaces implemented in the higher level code, which is here Activity) will be called.

这两个接口负责侦听在小部件派生的UI组件(如按钮或复选框)上可能发生的事件。因此,如果我们将这个示例与使用Java接口的早期回调示例进行比较,这两个接口作为回调接口。因此,高级代码(这里是活动)实现了这两个接口。每当一个小部件发生事件时,就会调用更高级别的代码(或者在更高级别的代码中实现的这些接口的方法)。

Now let me discuss the basic difference between Callback and Eventlistener pattern. As we have mentioned that using Callback, the Callee can notify only a single Caller. But in the case of EventListener pattern, any other part or class of the Application can register for the events that may occur on the Button or Checkbox. The example of this kind of class is the OtherClass. If you see the code of the OtherClass, you will find that it has registered itself as a listener to the ClickEvent that may occur in the Button defined in the Activity. Interesting part is that, besides the Activity ( the Caller), this OtherClass will also be notified whenever the click event occurs on the Button.

现在让我讨论回调和Eventlistener模式的基本区别。正如我们前面提到的,使用回调时,Callee可以只通知一个调用者。但在EventListener模式的情况下,应用程序的任何其他部分或类都可以注册在按钮或复选框中可能发生的事件。这种类的例子是另一个类。如果您看到其他类的代码,您会发现它已经将自己注册为一个监听器,并将其注册为在活动中定义的按钮中可能发生的ClickEvent。有趣的是,除了活动(调用者)之外,在按钮上发生单击事件时,也会通知其他类。

#27


1  

[edited]when we have two functions say functionA and functionB,if functionA depends on functionB.

[编辑]当我们有两个函数时,functionA和functionB,如果functionA依赖于functionB。

then we call functionB as a callback function.this is widely used in Spring framework.

然后我们调用functionB作为回调函数。这在Spring框架中得到了广泛的应用。

如何用简单的英语解释回调?它们与从另一个函数调用一个函数有什么不同?

#28


1  

Think of a method as giving a task to a coworker. A simple task might be the following:

把一种方法看成是给同事一个任务。一个简单的任务可能是:

Solve these equations:
x + 2 = y
2 * x = 3 * y

Your coworker diligently does the math and gives you the following result:

你的同事认真地做了计算,并给出了如下结果:

x = -6
y = -4

But your coworker has a problem, he doesn't always understand notations, such as ^, but he does understand them by their description. Such as exponent. Everytime he finds one of these you get back the following:

但是你的同事有一个问题,他并不总是理解符号,比如^,但是他也理解他们的描述。如指数。每次他发现其中的一个,你就会得到以下信息:

I don't understand "^"

This requires you to rewrite your entire instruction set again after explaining what the character means to your coworker, and he doesn't always remember in between questions. And he has difficulty remembering your tips as well, such as just ask me. He always follows your written directions as best he can however.

这就要求你在向你的同事解释这个角色的意思之后,再一次重写你的整个指令集,而且他也不总是在问题之间记得。他也很难记住你的建议,比如问我。他总是尽可能地听从你的书面指示。

You think of a solution, you just add the following to all of your instructions:

你想到一个解决方案,你只需在你的所有指令中加上以下内容:

If you have any questions about symbols, call me at extension 1234 and I will tell you its name.

Now whenever he has a problem he calls you and asks, rather than giving you a bad response and making the process restart.

现在,只要他有问题,他就会打电话问你,而不是给你一个糟糕的答复,让程序重新启动。

#29


0  

Callbacks allows you to insert your own code into another block of code to be executed at another time, that modifies or adds to the behavior of that other block of code to suit your needs. You gain flexibility and customizability while being able to have more maintainable code.

回调允许您将自己的代码插入到另一个代码块中,以便在另一个时间执行,从而修改或添加其他代码块的行为,以满足您的需要。您可以获得灵活性和可定制性,同时能够拥有更易于维护的代码。

Less hardcode = easier to maintain and change = less time = more business value = awesomeness.

更少的硬编码=更容易维护和更改=更少的时间=更多的业务价值= awesomeness。

For example, in javascript, using Underscore.js, you could find all even elements in an array like this:

例如,在javascript中,使用下划线。js,你可以在这样的数组中找到所有的元素:

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]

Example courtesy of Underscore.js: http://documentcloud.github.com/underscore/#filter

强调礼貌的示例。js:http://documentcloud.github.com/underscore/ #过滤器

#30


0  

This of it in terms of downloading a webpage:

就下载网页而言:

Your program runs on a cellphone and is requesting the webpage http://www.google.com. If you write your program synchronously, the function you write to download the data will be running continuously until all the data is download. This means your UI will not refresh and will basically appear frozen. If you write your program using callbacks, you request the data and say "execute this function when you've finished." This allows the UI to still allow user interaction while the file is downloading. Once the webpage has finished downloading, your result function (callback) is called and you can handle the data.

你的程序运行在一个手机上,并请求网页http://www.google.com。如果您同步编写程序,您编写的函数下载数据将持续运行,直到所有数据都被下载。这意味着您的UI将不会刷新,并且基本上会出现冻结。如果您使用回调编写程序,则请求数据并表示“完成后执行此函数”。这允许UI在文件下载时仍然允许用户交互。一旦网页下载完毕,你的结果函数(回调)就会被调用,你就可以处理数据了。

Basically, it allows you to request something and continue executing while waiting for the result. Once the result comes back to you via a callback function, you can pick up the operation where it left off.

基本上,它允许您在等待结果时请求某些东西并继续执行。一旦结果通过一个回调函数返回给您,您就可以在它停止的地方进行操作。