Что такое функция обратного вызова?

Что такое функция обратного вызова?

23 ответа

Разработчики часто смущаются тем, что такое обратный вызов из-за названия проклятой вещи.

Функция обратного вызова - это функция, которая:

  • доступ к другой функции, и
  • вызывается после первой функции, если эта первая функция завершается

Хороший способ представить, как работает функция обратного вызова, состоит в том, что это функция, которая "вызываетсясзади" функции, в которую она передается.

Может быть, лучшим именем будет функция "вызов после".

Эта конструкция очень полезна для асинхронного поведения, когда мы хотим, чтобы действие происходило всякий раз, когда завершается предыдущее событие.

псевдокод:

// A function which accepts another function as an argument
// (and will automatically invoke that function when it completes - note that there is no explicit call to callbackFunction)
funct printANumber(int number, funct callbackFunction) {
    printout("The number you provided is: " + number);
}

// a function which we will use in a driver function as a callback function
funct printFinishMessage() {
    printout("I have finished printing numbers.");
}

// Driver method
funct event() {
   printANumber(6, printFinishMessage);
}

Результат, если вы вызвали event():

The number you provided is: 6
I have finished printing numbers.

Порядок вывода здесь важен. Поскольку функции обратного вызова вызываются впоследствии, "Я закончил печатать номера" печатается последним, а не первым.

Обратные вызовы являются так называемыми из-за их использования с языками указателей. Если вы не используете один из них, не работайте над именем "обратный вызов". Просто поймите, что это просто имя для описания метода, который предоставляется в качестве аргумента для другого метода, например, когда вызывается родительский метод (любое условие, такое как нажатие кнопки, отметка таймера и т. Д.) И его тело метода завершается, затем вызывается функция обратного вызова.

Некоторые языки поддерживают конструкции, в которых поддерживаются несколько аргументов функции обратного вызова, и вызываются в зависимости от завершения родительской функции (т. Е. Один обратный вызов вызывается в случае успешного завершения родительской функции, другой вызывается в том случае, если родительская функция выбрасывает конкретная ошибка и т. д.).

Непрозрачное определение

Функция обратного вызова - это функция, которую вы предоставляете другому фрагменту кода, что позволяет ему вызываться этим кодом.

Придуманный пример

Зачем тебе это делать? Допустим, есть служба, которую нужно вызвать. Если сервис возвращается сразу, вы просто:

  1. Назови это
  2. Ждать результата
  3. Продолжайте, как только появится результат

Например, предположим, что служба была factorial функция. Когда вы хотите значение 5! Вы бы призвали factorial(5) и будут выполнены следующие шаги:

  1. Ваше текущее местоположение выполнения сохранено (в стеке, но это не важно)

  2. Исполнение передано factorial

  3. когда factorial завершает, он помещает результат туда, где вы можете получить к нему

  4. Казнь возвращается туда, где она была в [1]

Теперь предположим factorial Это заняло очень много времени, потому что вы даете ему огромные цифры, и он должен работать на каком-то суперкомпьютерном кластере. Допустим, вы ожидаете, что это займет 5 минут, чтобы вернуть ваш результат. Вы могли бы:

  1. Сохраняйте свой дизайн и запускайте программу ночью, когда вы спите, чтобы не смотреть на экран половину времени

  2. Разработайте свою программу, чтобы делать другие вещи, пока factorial делает свое дело

Если вы выберете второй вариант, обратные вызовы могут работать на вас.

Сквозной дизайн

Для того, чтобы использовать шаблон обратного вызова, вам нужно иметь возможность звонить factorial следующим образом:

factorial(really_big_number, what_to_do_with_the_result)

Второй параметр, what_to_do_with_the_result это функция, которую вы отправляете factorial в надежде, что factorial позвоню по его результату перед возвратом.

Да это значит что factorial должен быть написан для поддержки обратных вызовов.

Теперь предположим, что вы хотите иметь возможность передать параметр в ваш обратный вызов. Теперь вы не можете, потому что вы не будете называть это, factorial является. Так factorial должен быть написан, чтобы позволить вам передать ваши параметры, и он просто передаст их вашему обратному вызову, когда вызовет его. Это может выглядеть так:

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

Теперь, когда factorial позволяет этот шаблон, ваш обратный вызов может выглядеть так:

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

и ваш звонок factorial было бы

factorial(42, logIt, logger)

Что делать, если вы хотите вернуть что-то из logIt? Ну, ты не можешь, потому что factorial не обращая на это внимания.

Ну почему не могу factorial просто вернуть то, что возвращает ваш обратный вызов?

Сделать это неблокирующим

Поскольку выполнение должно быть передано обратному вызову, когда factorial закончен, он действительно не должен ничего возвращать вызывающей стороне. И в идеале, он каким-то образом запустит свою работу в другом потоке / процессе / машине и сразу же вернется, чтобы вы могли продолжить, возможно, что-то вроде этого:

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

Теперь это "асинхронный вызов", что означает, что когда вы вызываете его, он немедленно возвращается, но еще не выполнил свою работу. Таким образом, вам нужны механизмы, чтобы проверить его и получить его результат после его завершения, и ваша программа стала более сложной в этом процессе.

И, кстати, используя этот шаблон factorial_worker_task может запустить ваш обратный вызов асинхронно и немедленно вернуться.

Ну так что ты делаешь?

Ответ заключается в том, чтобы оставаться в рамках модели обратного вызова. Всякий раз, когда вы хотите написать

a = f()
g(a)

а также f должен вызываться асинхронно, вместо этого вы будете писать

f(g)

где g передается в качестве обратного вызова.

Это в корне меняет топологию потока вашей программы и требует некоторого привыкания.

Ваш язык программирования может очень вам помочь, предоставляя вам возможность создавать функции на лету. В приведенном выше коде функция g может быть как маленький print (2*a+1), Если ваш язык требует, чтобы вы определили это как отдельную функцию с совершенно ненужным именем и подписью, то ваша жизнь станет неприятной, если вы будете часто использовать этот шаблон.

Если, с другой стороны, ваш язык позволяет вам создавать лямбды, то вы в гораздо лучшей форме. Затем вы в конечном итоге написать что-то вроде

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

что намного приятнее.

Как пройти обратный звонок

Как бы вы передали функцию обратного вызова factorial? Ну, вы могли бы сделать это несколькими способами.

  1. Если вызываемая функция выполняется в том же процессе, вы можете передать указатель на функцию

  2. Или, может быть, вы хотите сохранить словарь fn name --> fn ptr в вашей программе, в этом случае вы можете передать имя

  3. Возможно, ваш язык позволяет вам определять функцию на месте, возможно, как лямбда! Внутренне это создает какой-то объект и передает указатель, но вам не нужно об этом беспокоиться.

  4. Возможно, вызываемая вами функция выполняется на совершенно отдельной машине, и вы вызываете ее, используя сетевой протокол, такой как HTTP. Вы можете представить свой обратный вызов как функцию, вызываемую по HTTP, и передать ее URL.

Вы поняли идею.

Недавний рост обратных вызовов

В эту эру Интернета, в которую мы вступили, службы, к которым мы обращаемся, часто работают по сети Мы часто не имеем никакого контроля над этими службами, то есть мы не писали их, мы не поддерживаем их, мы не можем гарантировать, что они работают или как они работают.

Но мы не можем ожидать, что наши программы будут блокироваться, пока мы ожидаем ответа этих служб. Осознавая это, поставщики услуг часто разрабатывают API, используя шаблон обратного вызова.

JavaScript очень хорошо поддерживает обратные вызовы, например, с лямбдами и замыканиями. И в мире JavaScript много активности, как в браузере, так и на сервере. Есть даже платформы JavaScript, разрабатываемые для мобильных устройств.

По мере продвижения вперед все больше и больше людей будут писать асинхронный код, для которого это понимание будет необходимо.

Обратите внимание, что обратный вызов - это одно слово.

Страница обратного вызова Википедии объясняет это очень хорошо.

цитата со страницы википедии:

В компьютерном программировании обратный вызов - это ссылка на исполняемый код или фрагмент исполняемого кода, который передается в качестве аргумента другому коду. Это позволяет программному уровню более низкого уровня вызывать подпрограмму (или функцию), определенную на уровне более высокого уровня.

Давайте будем простыми. Что такое функция обратного вызова?

Пример притчей и аналогиями

У меня есть секретарь. Каждый день я прошу ее: (i) отвезти исходящую почту фирмы на почту, а после того, как она это сделает, выполнить: (ii) любую задачу, которую я написал для нее на одной из этих записок.

Теперь, какова задача на заметку? Задача меняется день ото дня.

Предположим, именно в этот день я требую от нее распечатать некоторые документы. Поэтому я записываю это в заметку и прикрепляю ее к ее столу вместе с исходящей почтой, которую она должна отправить.

В итоге:

  1. во-первых, ей нужно отправить письмо и
  2. сразу после этого ей нужно распечатать некоторые документы.

Функция обратного вызова - это вторая задача: распечатать эти документы. Потому что это делается ПОСЛЕ того, как почта отбрасывается, а также потому, что ей дается липкая записка с указанием распечатать документ вместе с почтой, в которой она нуждается больше всего.

Давайте теперь связать это с лексикой программирования

  • Имя метода в этом случае: DropOffMail.
  • И функция обратного вызова: PrintOffDocuments. PrintOffDocuments является функцией обратного вызова, потому что мы хотим, чтобы секретарь делал это, только после запуска DropOffMail.
  • Поэтому я бы "передал: PrintOffDocuments в качестве" аргумента "методу DropOffMail. Это важный момент.

Вот и все. Ничего более. Я надеюсь, что это прояснилось для вас - и если нет, оставьте комментарий, и я сделаю все возможное, чтобы уточнить.

Ответ непрофессионала будет таким, что это функция, которая вызывается не вами, а пользователем или браузером после определенного события или после обработки некоторого кода.

Функция обратного вызова - это функция, которая должна вызываться при выполнении определенного условия. Вместо немедленного вызова, функция обратного вызова вызывается в определенный момент в будущем.

Обычно он используется, когда запускается задача, которая завершится асинхронно (т.е. завершится через некоторое время после возврата вызывающей функции).

Например, функция для запроса веб-страницы может потребовать, чтобы ее вызывающая сторона предоставила функцию обратного вызова, которая будет вызываться после завершения загрузки веб-страницы.

Обратные вызовы проще всего описать в терминах телефонной системы. Функциональный вызов аналогичен вызову кого-либо по телефону, задает ей вопрос, получает ответ и вешает трубку; добавление обратного вызова изменяет аналогию, так что после того, как вы зададите ей вопрос, вы также дадите ей свое имя и номер, чтобы она могла перезвонить вам с ответом.

- Пол Якубик, "Реализации обратного вызова в C++"

Я полагаю, что этот жаргонный словарь по ошибке использовался во многих местах. Мое определение будет что-то вроде:

Функция обратного вызова - это функция, которую вы передаете кому-то и позволяете ему вызывать ее в определенный момент времени.

Я думаю, что люди просто читают первое предложение определения вики:

обратный вызов - это ссылка на исполняемый код или фрагмент исполняемого кода, который передается в качестве аргумента другому коду.

Я работал со многими API, вижу множество плохих примеров. Многие люди склонны называть указатель на функцию (ссылка на исполняемый код) или анонимные функции (часть исполняемого кода) "обратным вызовом", если они являются просто функциями, зачем вам другое имя для этого?

На самом деле, только второе предложение в определении вики раскрывает разницу между функцией обратного вызова и нормальной функцией:

Это позволяет программному уровню более низкого уровня вызывать подпрограмму (или функцию), определенную на уровне более высокого уровня.

так что разница в том, кому вы собираетесь передать функцию и как будет вызываться ваша переданная функция. Если вы просто определяете функцию, передаете ее другой функции и вызываете ее непосредственно в теле этой функции, не вызывайте ее как обратный вызов. Определение гласит, что переданная вами функция будет вызываться функцией "более низкого уровня".

Я надеюсь, что люди могут перестать использовать это слово в неоднозначном контексте, оно не может помочь людям понять лучше только хуже.

Что такое обратный звонок?

  • В общем, звонили, чтобы вернуть тот, который кто-то получил.
  • В вычислениях обратный вызов - это часть исполняемого кода, которая передается в качестве аргумента другому коду. Когда функция завершает свою работу (или когда происходит какое-то событие), она вызывает функцию обратного вызова (она вызывает вас - отсюда и имя).

Что такое функция обратного вызова?

  • функция обратного вызова похожа на Слугу, который "перезванивает" своему Мастеру, когда он завершил задачу.
  • функция обратного вызова - это функция, которая передается другой функции (давайте назовем эту другую функцию otherFunction) в качестве параметра, и функция обратного вызова вызывается (или выполняется) внутри otherFunction,

    функция action(x, y, callback) { return callback(x, y); }

    умножение функций (x, y) { return x * y; }

    сложение функции (x, y) { return x + y; }

    оповещение (действие (10, 10, умножение)); // вывод: 100

    оповещение (действие (10, 10, дополнение)); // вывод: 20

В SOA обратный вызов позволяет подключаемым модулям получать доступ к сервисам из контейнера / среды.

Аналогия: обратные вызовы. Асинхронный. Неблокируемая
Пример из реальной жизни для обратного вызова

Это делает обратные вызовы похожими на операторы возврата в конце методов.

Я не уверен, что это то, что они есть.

Я думаю, что обратные вызовы на самом деле являются вызовом функции, как следствие вызова и завершения другой функции.

Я также думаю, что обратные вызовы предназначены для обращения к исходному вызову, в некотором роде "эй! То, что вы просили? Я сделал это - просто подумал, что сообщу вам - вернемся к вам".

Call After будет лучшим именем, чем глупое имя, callback. Когда или если условие выполняется внутри функции, вызовите другую функцию, функцию Call After, полученную в качестве аргумента.

Вместо того, чтобы жестко кодировать внутреннюю функцию внутри функции, пишется функция, принимающая в качестве аргумента уже написанную функцию Call After. Вызов Call After может вызываться на основе изменений состояния, обнаруженных кодом в функции, получающей аргумент.

Функция обратного вызова - это функция, которую вы указываете существующей функции / методу, которая вызывается, когда действие завершено, требует дополнительной обработки и т. Д.

Например, в Javascript или, более конкретно, в jQuery вы можете указать аргумент обратного вызова, который будет вызываться после завершения анимации.

В PHP preg_replace_callback() Функция позволяет вам предоставить функцию, которая будет вызываться при сопоставлении регулярного выражения, передавая строку (и), совпадающую с аргументами.

Посмотрите на изображение:)вот как это работает

Основная программа вызывает библиотечную функцию (которая также может быть функцией системного уровня) с именем функции обратного вызова. Эта функция обратного вызова может быть реализована несколькими способами. Основная программа выбирает один обратный вызов согласно требованию.

Наконец, библиотечная функция вызывает функцию обратного вызова во время выполнения.

Простой ответ на этот вопрос заключается в том, что функция обратного вызова - это функция, которая вызывается через указатель на функцию. Если вы передаете указатель (адрес) функции в качестве аргумента другому, когда этот указатель используется для вызова функции, на которую он указывает, говорят, что обратный вызов сделан

Предположим, у нас есть функция sort(int *arraytobesorted,void (*algorithmchosen)(void)) где он может принять указатель на функцию в качестве аргумента, который может быть использован в какой-то момент sort()Реализация. Затем, здесь код, к которому обращается указатель на функцию algorithmchosen называется функцией обратного вызова.

И видим преимущество в том, что мы можем выбрать любой алгоритм, например:

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

Которые, скажем, были реализованы с прототипом:

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

Эта концепция используется для достижения полиморфизма в объектно-ориентированном программировании.

"В компьютерном программировании обратный вызов - это ссылка на исполняемый код или фрагмент исполняемого кода, который передается в качестве аргумента другому коду. Это позволяет программному уровню более низкого уровня вызывать подпрограмму (или функцию), определенную в более высоком уровне ". - Википедия

Обратный вызов в C с использованием указателя на функцию

В C обратный вызов реализован с использованием указателя функций. Указатель на функцию - как следует из названия, является указателем на функцию.

Например, int (*ptrFunc) ();

Здесь ptrFunc - указатель на функцию, которая не принимает аргументов и возвращает целое число. НЕ забывайте ставить в скобках, в противном случае компилятор будет считать, что ptrFunc - это обычное имя функции, которое ничего не берет и возвращает указатель на целое число.

Вот некоторый код для демонстрации указателя на функцию.

#include<stdio.h>
int func(int, int);
int main(void)
{
    int result1,result2;
    /* declaring a pointer to a function which takes
       two int arguments and returns an integer as result */
    int (*ptrFunc)(int,int);

    /* assigning ptrFunc to func's address */                    
    ptrFunc=func;

    /* calling func() through explicit dereference */
    result1 = (*ptrFunc)(10,20);

    /* calling func() through implicit dereference */        
    result2 = ptrFunc(10,20);            
    printf("result1 = %d result2 = %d\n",result1,result2);
    return 0;
}

int func(int x, int y)
{
    return x+y;
}

Теперь давайте попробуем понять концепцию Callback в C, используя указатель на функцию.

Полная программа имеет три файла: callback.c, reg_callback.h и reg_callback.c.

/* callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* callback function definition goes here */
void my_callback(void)
{
    printf("inside my_callback\n");
}

int main(void)
{
    /* initialize function pointer to
    my_callback */
    callback ptr_my_callback=my_callback;                        
    printf("This is a program demonstrating function callback\n");
    /* register our callback function */
    register_callback(ptr_my_callback);                          
    printf("back inside main program\n");
    return 0;
}

/* reg_callback.h */
typedef void (*callback)(void);
void register_callback(callback ptr_reg_callback);


/* reg_callback.c */
#include<stdio.h>
#include"reg_callback.h"

/* registration goes here */
void register_callback(callback ptr_reg_callback)
{
    printf("inside register_callback\n");
    /* calling our callback function my_callback */
    (*ptr_reg_callback)();                               
}

Если мы запустим эту программу, вывод будет

Это программа, демонстрирующая обратный вызов функции внутри register_callback внутри my_callback назад внутри основной программы

Функция верхнего уровня вызывает функцию нижнего уровня как обычный вызов, а механизм обратного вызова позволяет функции нижнего уровня вызывать функцию верхнего уровня через указатель на функцию обратного вызова.

Обратный вызов в Java с использованием интерфейса

В Java нет концепции указателя функции. Он реализует механизм обратного вызова через механизм интерфейса. Здесь вместо указателя функции мы объявляем интерфейс, имеющий метод, который будет вызван, когда вызываемый объект завершит свою задачу.

Позвольте мне продемонстрировать это на примере:

Интерфейс обратного вызова

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

Абонент или класс более высокого уровня

public Class Caller implements Callback
{
Callee ce = new Callee(this); //pass self to the callee

//Other functionality
//Call the Asynctask
ce.doAsynctask();

public void notify(Result result){
//Got the result after the callee has finished the task
//Can do whatever i want with the result
}
}

Функция 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
}
}

Обратный вызов с использованием шаблона EventListener

  • Элемент списка

Этот шаблон используется для уведомления от 0 до n номеров Наблюдателей / Слушателей о том, что определенная задача выполнена

  • Элемент списка

Разница между механизмом обратного вызова и механизмом EventListener/Observer заключается в том, что при обратном вызове вызываемый абонент уведомляет единственного вызывающего абонента, в то время как в Eventlisener/Observer вызываемый абонент может уведомить любого, кто заинтересован в этом событии (уведомление может передаваться некоторым другим частям приложение, которое не вызвало задачу)

Позвольте мне объяснить это на примере.

Интерфейс событий

public interface Events {

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

Виджет класса

package com.som_itsolutions.training.java.exampleeventlistener;

import java.util.ArrayList;
import java.util.Iterator;

public class Widget implements Events{

    ArrayList<OnClickEventListener> mClickEventListener = new ArrayList<OnClickEventListener>(); 
    ArrayList<OnLongClickEventListener> mLongClickEventListener = new ArrayList<OnLongClickEventListener>();

    @Override
    public void clickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnClickEventListener> it = mClickEventListener.iterator();
                while(it.hasNext()){
                    OnClickEventListener li = it.next();
                    li.onClick(this);
                }   
    }
    @Override
    public void longClickEvent() {
        // TODO Auto-generated method stub
        Iterator<OnLongClickEventListener> it = mLongClickEventListener.iterator();
        while(it.hasNext()){
            OnLongClickEventListener li = it.next();
            li.onLongClick(this);
        }

    }

    public interface OnClickEventListener
    {
        public void onClick (Widget source);
    }

    public interface OnLongClickEventListener
    {
        public void onLongClick (Widget source);
    }

    public void setOnClickEventListner(OnClickEventListener li){
        mClickEventListener.add(li);
    }
    public void setOnLongClickEventListner(OnLongClickEventListener li){
        mLongClickEventListener.add(li);
    }
}

Кнопка класса

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

Флажок класса

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

Класс деятельности

пакет com.som_itsolutions.training.java.exampleeventlistener;

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

Другой класс

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

Основной класс

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

Как видно из приведенного выше кода, у нас есть интерфейс с названием events, который в основном перечисляет все события, которые могут произойти для нашего приложения. Класс Widget является базовым классом для всех компонентов пользовательского интерфейса, таких как Button, Checkbox. Эти компоненты пользовательского интерфейса являются объектами, которые фактически получают события из кода платформы. Класс Widget реализует интерфейс Events, а также имеет два вложенных интерфейса: OnClickEventListener и OnLongClickEventListener.

Эти два интерфейса отвечают за прослушивание событий, которые могут произойти в компонентах пользовательского интерфейса, производных от виджетов, таких как Button или Checkbox. Поэтому, если мы сравним этот пример с более ранним примером Callback с использованием интерфейса Java, эти два интерфейса будут работать как интерфейс Callback. Таким образом, код более высокого уровня (Здесь Activity) реализует эти два интерфейса. И всякий раз, когда событие происходит с виджетом, будет вызываться код более высокого уровня (или метод этих интерфейсов, реализованный в коде более высокого уровня, который здесь называется Activity).

Теперь позвольте мне обсудить основное различие между шаблонами Callback и Eventlistener. Как мы уже упоминали, используя Callback, Callee может уведомить только одного абонента. Но в случае шаблона EventListener любая другая часть или класс приложения может регистрироваться для событий, которые могут происходить на кнопке или флажке. Примером такого класса является класс Other Class. Если вы увидите код Other Class, вы обнаружите, что он зарегистрировался в качестве прослушивателя ClickEvent, что может происходить в кнопке, определенной в Activity. Интересно, что помимо Activity (Вызывающий объект), этот Other Class также будет уведомляться всякий раз, когда происходит событие нажатия кнопки.

A callback is an idea of passing a function as a parameter to another function and have this one invoked once the process has completed.

If you get the concept of callback through awesome answers above, I recommend you should learn the background of its idea.

"What made them(Computer-Scientists) develop callback?" You might learn a problem, which is blocking.(especially blocking UI) And callback is not the only solution to it. There are a lot of other solutions(ex: Thread, Futures, Promises...).

Функция обратного вызова - это функция, которую вы передаете (в качестве ссылки или указателя) определенной функции или объекту. Эта функция или объект будут вызывать эту функцию в любое время позже, возможно, несколько раз, для любых целей:

  • уведомление о завершении задачи
  • запрос сравнения между двумя элементами (как в c qsort())
  • отчетность о ходе процесса
  • уведомляющие события
  • делегирование экземпляра объекта
  • делегирование картины области

...

Таким образом, описание обратного вызова как функции, вызываемой в конце другой функции или задачи, чрезмерно упрощается (даже если это общий случай использования).

Одной из важных областей использования является то, что вы регистрируете одну из своих функций как дескриптор (то есть обратный вызов), а затем отправляете сообщение / вызываете какую-то функцию для выполнения какой-либо работы или обработки. Теперь, когда обработка завершена, вызываемая функция будет вызывать нашу зарегистрированную функцию (т. Е. Теперь выполнен обратный вызов), что указывает на то, что обработка завершена.
Эта ссылка на Википедию довольно хорошо объясняет графически.

Я опоздал на 13 лет к игре с этим ответом, но, узнав его сам, я подумал, что добавлю сюда еще один ответ на случай, если кто-то сбит с толку, как я.

Другие ответы суммируют суть вопроса «Что такое обратный вызов?»

Это просто функция, которая вызывает другую функцию, когда что-то завершено.

Что меня поразило, так это примеры: «Ты сделал это, а теперь сделай то». Например , ПОЧЕМУ я должен использовать это так, когда я могу просто вызвать метод или функцию самостоятельно?

Итак, вот быстрый пример из реального мира, который, надеюсь, кого-то зацепит.

Ультра псевдокод

Сначала основная проблема, с которой вы столкнетесь....

      Multithreaded Method(Some arguments)
  {
    Do fancy multithreaded stuff....
  }

Main()
 {
   Some stuff I wanna do = some tasks
   Multhreaded Method(Some stuff I wanna do)
 }

Если вы запустите это без какого-либо обратного вызова, ваша программа будет выглядеть так, как будто она только что вышла. Потому что «причудливые многопоточные вещи» выполняются в другом процессе.

Итак, вы чешете затылок и думаете: «Ну, черт возьми, как я узнаю, когда это будет сделано??»

БУМ... ОБРАТНЫЙ ЗВОНОК

      IsItDone = false

Callback()
{
  print("Hey, I'm done")
  IsItDone = true
}
  
Multithreaded Method(Some arguments, Function callback)
  {
    Do fancy multithreaded stuff....
  }

Main()
 {
   Some stuff I wanna do = some tasks
   Multhreaded Method(Some stuff I wanna do,Callback)

   while(!IsItDone)
     Wait a bit
 }

Это 100% не лучший способ реализации, я просто хотел привести наглядный пример.

Так что это не просто "Что такое обратный вызов?" Это «Что такое обратный вызов и что он мне дает?»

Функция обратного вызова, также известная как функция высшего порядка, является функцией, которая передается другой функции в качестве параметра, и функция обратного вызова вызывается (или выполняется) внутри родительской функции.

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

Здесь мы передаем функцию в качестве параметра методу click. И метод click вызовет (или выполнит) функцию обратного вызова, которую мы передали ему.

Функция обратного вызова Функция, которая передана другой функции в качестве аргумента.

function test_function(){       
 alert("Hello world");  
} 

setTimeout(test_function, 2000);

Примечание. В приведенном выше примере test_function используется в качестве аргумента для функции setTimeout.

Обратный вызов — это функция, которая передается другой функции в качестве аргумента или параметра.Зачем нам нужна функция обратного вызова?Мы используем обратный вызов, поэтому нам не нужно ждать ответа.

Другие вопросы по тегам