Как объяснить обратные вызовы на простом английском языке? Как они отличаются от вызова одной функции от другой функции?

Как объяснить обратные вызовы на простом английском языке? Как они отличаются от вызова одной функции из другой функции, принимая какой-то контекст от вызывающей функции? Как объяснить их власть начинающему программисту?

Часто приложение должно выполнять различные функции, основанные на его контексте / состоянии. Для этого мы используем переменную, в которой мы будем хранить информацию о вызываемой функции. В соответствии с его потребностью приложение установит эту переменную с информацией о вызываемой функции и вызовет функцию с использованием той же переменной.

В 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] 

Я собираюсь попытаться сохранить это мертвым просто. «Обратный вызов» – это любая функция, вызываемая другой функцией, которая принимает первую функцию в качестве параметра. Много раз «обратный вызов» – это функция, которая вызывается, когда что-то происходит. Это можно назвать «событием» в программистах.

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

Вы могли бы сказать им, чтобы получить пакет и донести его до соседей. Если ваш супруг был таким же глупым, как компьютер, они сидели бы у двери и дожидались пакета до тех пор, пока он не придет (НЕ ДЕЛАЯ ЧТО-НИБУДЬ), а затем, когда он придет, они передадут его соседям. Но есть лучший способ. Скажите своему супругу, что, когда они получают пакет, они должны принести его соседям. Тогда они могут нормально жить, пока они не получат пакет.

В нашем примере получение пакета – это «событие», а его приведение к соседям – это «обратный вызов». Ваш супруг «запускает» ваши инструкции, чтобы передать пакет только после того, как пакет поступит. Намного лучше!

Такое мышление очевидно в повседневной жизни, но компьютеры не имеют такого же здравого смысла. Подумайте, как обычно программисты записывают файл:

 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 

Здесь мы WAIT для открытия файла, прежде чем мы напишем ему. Это «блокирует» stream исполнения, и наша программа не может выполнять какие-либо другие действия, которые это может потребоваться! Что, если бы мы могли это сделать:

 # 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! 

Оказывается, мы делаем это с некоторыми языками и структурами. Это круто! Проверьте Node.js, чтобы получить реальную практику с таким мышлением.

Как объяснить обратные вызовы на простом английском языке?

На простом английском языке функция обратного вызова похожа на Работника, который «обращается» к своему Менеджеру, когда он завершил задачу .

Как они отличаются от вызова одной функции из другой функции, принимая какой-то контекст от вызывающей функции?

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

Как объяснить их власть начинающему программисту?

Эффективность обратных вызовов можно легко увидеть на сайтах в стиле AJAX, которые должны извлекать данные с сервера. Загрузка новых данных может занять некоторое время. Без обратных вызовов весь пользовательский интерфейс «зависает» при загрузке новых данных, или вам нужно будет обновить всю страницу, а не только ее часть. С обратным вызовом вы можете вставить изображение «теперь загружать» и заменить его новыми данными после его загрузки.

Некоторый код без обратного вызова:

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

С обратным вызовом:

Вот пример с обратным вызовом, используя jQuery’s 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 } 

С закрытием:

Часто обратный вызов должен получить доступ к state от вызывающей функции, используя closure , которое подобно Работнику, которому требуется получить информацию от Менеджера, прежде чем он сможет выполнить свою Задачу . Чтобы создать closure , вы можете встроить функцию, чтобы она просматривала данные в вызывающем контексте:

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

Применение:

 // 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 от Дугласа Крокфорда :

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

Смотрите также:

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

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

 customizableFunc(customFunctionality) 

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

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

Хотя такого рода внедренные функциональные возможности часто называют «обратным вызовом», в этом нет ничего конъюнктивного. Очень очевидным примером является метод forEach, в котором настраиваемая функция предоставляется как аргумент, который должен применяться к каждому элементу массива для изменения массива.

Но это принципиально отличается от использования функций «обратного вызова» для асинхронного программирования , как в AJAX или node.js, или просто для назначения функциональности событиям взаимодействия с пользователем (например, щелчкам мыши). В этом случае вся идея состоит в том, чтобы дождаться события контингента перед выполнением пользовательских функций. Это очевидно в случае взаимодействия с пользователем, но также важно в процессах ввода / вывода (ввода / вывода), которые могут занять время, например, чтение файлов с диска. Именно здесь термин «обратный вызов» имеет наиболее очевидный смысл. Как только процесс ввода-вывода запускается (например, запрашивает чтение файла с диска или сервера для возврата данных из HTTP-запроса), асинхронная программа не ждет, когда она закончится. Он может выполнять любые задачи, запланированные на следующий день, и отвечать только с помощью пользовательских функций после того, как он был уведомлен о завершении чтения файла или HTTP-запроса (или его отказа) и что данные доступны для пользовательских функций. Это похоже на вызов бизнеса по телефону и оставление вашего номера «обратного вызова», поэтому они могут позвонить вам, когда кто-то сможет вернуться к вам. Это лучше, чем висит на линии, кто знает, как долго и не может заниматься другими делами.

Асинхронное использование по своей сути включает в себя некоторые способы прослушивания желаемого события (например, завершения процесса ввода-вывода), так что, когда это происходит (и только когда это происходит), выполняется пользовательская функция «обратного вызова». В очевидном примере AJAX, когда данные действительно поступают с сервера, функция «обратного вызова» запускается для использования этих данных для изменения DOM и, следовательно, для этого перерисовывает окно браузера.

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

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

Общим предметом многих бумажных форм является «Человек, который следует звонить в случае чрезвычайной ситуации». Там есть пустая строка. Вы пишете чье-то имя и номер телефона. Если возникает чрезвычайная ситуация, то этот человек получает вызов.

  • Каждый получает ту же пустую форму, но
  • Каждый может написать другой номер экстренного контакта.

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

Пример 1:

Обратные вызовы используются как настраиваемые методы, возможно, для добавления / изменения поведения программы. Например, возьмите некоторый C-код, который выполняет функцию, но не знает, как печатать выходные данные. Все, что он может сделать, это сделать строку. Когда он пытается понять, что делать со строкой, он видит пустую строку. Но программист дал вам пробел, чтобы написать обратный вызов!

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

  • Чистая переменная в модуле / коде является пустой строкой,
  • set_print_callback – это карандаш,
  • и the_callback – это ваша информация, которую вы заполняете.

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

Пример 2:

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

Программирование Gui работает так же. Когда нажимается кнопка, программа должна выяснить, что делать дальше. Он идет и ищет обратный вызов. Этот обратный вызов находится в пробеле с надписью «Вот что вы делаете, когда Button1 нажата»

Большинство IDE автоматически заполнят пробел для вас (напишите базовый метод), когда вы попросите его (например, button1_clicked ). Однако этот пробел может иметь любой метод, который вы хорошо проглотите . Вы можете вызвать метод run_computations или butter_the_biscuits если вы поместили это имя обратного вызова в правильный пробел. Вы можете поместить «555-555-1212» в номер экстренной службы пустым. Это не имеет большого смысла, но это допустимо.


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

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

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

Всегда лучше начинать с примера :).

Предположим, у вас есть два модуля A и B.

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

Таким образом, все B теперь нужно делать, это «обратный вызов» в модуль A, когда определенное событие / условие происходит с помощью указателя функции. A может выполнять дополнительную обработку внутри функции обратного вызова.

*) Явное преимущество здесь в том, что вы абстрагируете все, что касается модуля A от модуля B. Модуль B не должен заботиться о том, кто / какой модуль A.

Представьте себе, что вам нужна функция, которая возвращает квадрат 10, чтобы написать функцию:

 function tenSquared() {return 10*10;} 

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

 function nineSquared() {return 9*9;} 

В конце концов вы замените все из них на общую функцию:

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

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

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

Позже вы хотите, чтобы одна и та же функция вызывала doB, вместо этого вы могли дублировать всю функцию:

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

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

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

Тогда вам просто нужно вызвать compute (doA) и вычислить (doB).

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

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

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

Аналогия ожидания прибытия посылки, которая использовалась другими ответами, является хорошей для объяснения того и другого. В компьютерной программе вы сказали бы, что компьютер ожидает посылку. Обычно он сидел бы там и ждал (и ничего не делал) до тех пор, пока посылка не поступит, возможно, бесконечно, если она не придет. Для людей это звучит глупо, но без дальнейших мер это совершенно естественно для компьютера.

Теперь обратным вызовом будет звонок в вашей входной двери. Вы предоставляете услугу посылки, чтобы сообщить вам о прибытии посылки, чтобы они не знали, где (даже если) вы находитесь в доме или как работает звонок. (Например, некоторые «колокола» фактически отправляют телефонный звонок.) Поскольку вы предоставили «функцию обратного вызова», которую можно «вызвать» в любое время, вне контекста, вы можете теперь перестать сидеть у переднего крыльца и «обрабатывать событие “(прибытие посылки) всякий раз, когда это время.

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

В Python, например,

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

grabDBValue может быть записано только для получения значения из базы данных, а затем позволяет указать, что на самом деле делать со значением, поэтому оно принимает функцию. Вы не знаете, когда или если grabDBValue вернется, но если / когда это произойдет, вы знаете, что хотите. Здесь я передаю анонимную функцию (или лямбду ), которая отправляет значение в окно графического интерфейса. Я мог бы легко изменить поведение программы, выполнив следующие действия:

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

Обратные вызовы хорошо работают на языках, где функции являются значениями первого classа , такими же, как обычные целые числа, символьные строки, булевы и т. Д. В C вы можете «передавать» функцию вокруг, обходя указатель на нее, и вызывающий может ее использовать; в Java, вызывающий будет запрашивать статический class определенного типа с определенным именем метода, так как нет функций («методы», действительно) вне classов; и в большинстве других динамических языков вы можете просто передать функцию с простым синтаксисом.

Protip:

В языках с лексическим охватом (например, 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 в этом случае будет 6 потому что обратный вызов имеет доступ к переменным, объявленным в лексической среде, где он был определен. Лексический охват и анонимные обратные вызовы – это мощная комбинация, которая требует дальнейшего изучения для начинающего программиста.

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

Альтернативный метод – запустить этот код параллельно и продолжить свою работу. Но что, если ваш исходный код должен делать разные вещи в зависимости от ответа от кода, который он назвал? Ну, в этом случае вы можете передать имя / местоположение кода, который вы хотите вызвать, когда это будет сделано. Это «звонок назад».

Обычный код: Запросить информацию-> Информация о процессе-> Поделитесь результатами обработки-> Продолжайте делать другие вещи.

С обратными вызовами: Запросить информацию-> Информация о процессе-> Продолжать делать другие вещи. И в какой-то более поздний момент -> Сделка с результатами обработки.

Без обратного вызова ни другие специальные ресурсы программирования (например, streamи, и другие), программа представляет собой точно последовательность инструкций, которые последовательно выполняются один за другим и даже с определенным «динамическим поведением», определенным определенными условиями, всеми возможными сценариями должны быть предварительно запрограммированы .

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

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

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

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

Надеюсь, это объяснение может быть полезным.

Давайте притворимся, что вы должны дать мне потенциально долгосрочную задачу: получите имена первых пяти уникальных людей, с которыми вы сталкиваетесь. Это может занять несколько дней, если я нахожусь в малонаseleniumном районе. Вы не очень заинтересованы в том, чтобы сидеть на armх, пока я бегаю, поэтому вы говорите: «Когда у вас есть список, позвоните мне в свою камеру и прочитайте его мне. Вот номер».

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

В JavaScript это может выглядеть примерно так:

 var lottoNumbers = []; var callback = function(theNames) { for (var i=0; i 

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

Обратные вызовы наиболее легко описываются с точки зрения телефонной системы. Вызов функции аналогичен вызову кого-то по телефону, задавая ей вопрос, получая ответ и подвешивая; добавление обратного вызова изменяет аналогию, поэтому, задав ей вопрос, вы также дадите ей свое имя и номер, чтобы она могла перезвонить вам с ответом. – Павел Якубик, «Реализация обратного вызова в C ++»

Обратный вызов – это функция, которая будет вызываться второй функцией. Эта вторая функция не знает заранее, какую функцию она будет вызывать. Таким образом, идентификатор функции обратного вызова хранится где-то или передается второй функции в качестве параметра. Этот «идентификатор», в зависимости от языка программирования, может быть адресом обратного вызова или каким-либо другим указателем, или это может быть имя функции. Принцип тот же, мы храним или передаем некоторую информацию, которая однозначно идентифицирует функцию.

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

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

Кстати, в зависимости от языка программирования слово «функция» в приведенном выше обсуждении может быть заменено на «блок», «закрытие», «lambda» и т. Д.

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

function1(var1, var2) является обычным способом.

Что делать, если я хочу, чтобы var2 обрабатывался, а затем отправлялся в качестве аргумента? function1(var1, function2(var2))

Это один из видов обратного вызова – где function2 выполняет некоторый код и возвращает переменную обратно к исходной функции.

Метафорическое объяснение:

У меня есть посылка, которую я хочу достать другу, и я также хочу знать, когда мой друг получит ее.

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

(a) Я могу ждать в почтовом отделении, пока он не будет доставлен.

(б) Я получаю электронное письмо, когда оно будет доставлено.

Вариант (b) аналогичен обратному вызову.

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

  • Сначала покажите учащимся, как использовать и манипулировать переменными с помощью указателей, используя обычные идентификаторы переменных.
  • Затем научите их тому, что можно сделать только с указателями (например, передавая переменную по ссылке).
  • Затем сообщите им, как исполняемый код или функции похожи на некоторые другие данные (или переменные) в памяти. Таким образом, функции также имеют адреса или указатели.
  • Затем покажите им, как функции могут быть вызваны с указателями функций и сказать, что они называются обратными вызовами.
  • Теперь вопрос в том, почему все эти хлопоты для вызова некоторых функций? Какая польза? Подобно указателям данных, указатель функции aka callbacks имеет некоторые преимущества перед использованием обычных идентификаторов.
  • Первый из них: идентификаторы функций или имена функций не могут использоваться в качестве обычных данных. Я имею в виду, вы не можете создать структуру данных с функциями (например, с массивом или связанным списком функций). Но с обратными вызовами вы можете создать массив, связанный список или использовать их с другими данными, например, в словах пар ключ-значение или деревья или любыми другими вещами. Это мощная выгода. И другие преимущества на самом деле являются дочерними.
  • Наиболее частое использование обратных вызовов наблюдается при программировании драйверов событий. Если одна или несколько функций выполняются на основе некоторого входящего сигнала. С обратными вызовами может поддерживаться словарь для отображения сигналов с обратными вызовами. Тогда разрешение входного сигнала и выполнение соответствующего кода становятся намного проще.
  • Второе использование обратных вызовов, которые мне приходят в голову, – функции более высокого порядка. Функции, которые принимают другие функции в качестве входных аргументов. И для отправки функций в качестве аргументов нам нужны обратные вызовы. Примером может быть функция, которая принимает массив и обратный вызов. Затем он выполняет обратный вызов по каждому элементу массива и возвращает результаты в другом массиве. Если мы передадим функции удвоение обратного вызова, мы получим двузначный массив. Если мы пройдем квадратичный обратный вызов, мы получим квадраты. Для квадратных корней просто отправьте соответствующий обратный вызов. Это невозможно сделать с помощью обычных функций.

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

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:

  1. Check the window every 5 minutes to see if Joe is out
  2. Keep doing their thing until Joe rings the door bell.

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.

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 ie ring the door bell when he’s there.

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.

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.

Надеюсь, это поможет!

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.

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).

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

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

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”

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.

 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; ma=10; strcpy(mb,"123"); callback = (void*)cbfunc; /* point to callback function */ callback(&m); /* perform callback and pass in the param */ return 0; } 

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.

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.

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.

“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

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

For example, 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.

Here is some code to demonstrate the function pointer.

 #include 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.

 /* callback.c */ #include #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 #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

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

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

 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

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

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

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

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)

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 mClickEventListener = new ArrayList(); ArrayList mLongClickEventListener = new ArrayList(); @Override public void clickEvent() { // TODO Auto-generated method stub Iterator it = mClickEventListener.iterator(); while(it.hasNext()){ OnClickEventListener li = it.next(); li.onClick(this); } } @Override public void longClickEvent() { // TODO Auto-generated method stub Iterator 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); } } в package com.som_itsolutions.training.java.exampleeventlistener; import java.util.ArrayList; import java.util.Iterator; public class Widget implements Events{ ArrayList mClickEventListener = new ArrayList(); ArrayList mLongClickEventListener = new ArrayList(); @Override public void clickEvent() { // TODO Auto-generated method stub Iterator it = mClickEventListener.iterator(); while(it.hasNext()){ OnClickEventListener li = it.next(); li.onClick(this); } } @Override public void longClickEvent() { // TODO Auto-generated method stub Iterator 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); } } в package com.som_itsolutions.training.java.exampleeventlistener; import java.util.ArrayList; import java.util.Iterator; public class Widget implements Events{ ArrayList mClickEventListener = new ArrayList(); ArrayList mLongClickEventListener = new ArrayList(); @Override public void clickEvent() { // TODO Auto-generated method stub Iterator it = mClickEventListener.iterator(); while(it.hasNext()){ OnClickEventListener li = it.next(); li.onClick(this); } } @Override public void longClickEvent() { // TODO Auto-generated method stub Iterator 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

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

Основной 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

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.

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.

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

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

callback function wikipedia example

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.

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.

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

 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

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.

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.

  • Когда функция слишком длинная?
  • jquery - разница между $ .functionName и $ .fn.FunctionName
  • Как заставить функцию СУММ в MySQL возвращать '0', если значения не найдены?
  • Вычисление средней функции массива Swift
  • Выполнить функцию jQuery после выполнения другой функции
  • Как составить `не` с функцией произвольной arity?
  • Макро против функции в C
  • Имя таблицы как параметр функции PostgreSQL
  • Размер X, Y для массива в функции C
  • Как округлить до ближайшего 0,5?
  • Функция возвращает None без оператора return
  • Давайте будем гением компьютера.