@NkDev

Что такое обратный вызов в программировании?

Что такое обратные вызовы?
В чем их смысл и зачем нужны?
Почему они так называются?

Я знаю только что это функция которая передается как аргумент в другую функцию.
  • Вопрос задан
  • 286 просмотров
Решения вопроса 3
Обратный вызов (англ. callback) — это ещё одна функция, которую вызовут «потом».

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

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

Например, нужно выполнить HTTP запрос к далёкому серверу и получить от него ответ.

Тогда в функцию, которая займётся общением с далёким сервером, передают не только параметры запроса, но и callback-функцию, которая будет вызвана после получения ответа, с данными из ответа.
Ответ написан
bingo347
@bingo347
Бородатый программер
Что такое обратные вызовы?
Я знаю только что это функция которая передается как аргумент в другую функцию.
В принципе, можно и так сказать. Если быть более точным - это вызов функции переданной в качестве аргумента.
Почему они так называются?
Это игра слов. На английском callback - это не только обратный вызов, но и обратный звонок (по телефону). Данная абстракция позволяет вызываемому коду вызвать вызывающий код, подобно тому как собеседник может перезвонить Вам позднее, если Вы сообщите ему куда.
В чем их смысл и зачем нужны?
В принципе я уже ответил, они нужны для возможности вызываемому коду вызвать вызывающий код. Это позволяет строить высокоуровневые абстракции, вроде обобщенных функций или асинхронных функций.
Обобщенные функции позволяют не писать однотипный код, снижая тем самым вероятность ошибок, а с помощью обратных вызовов они могут принимать в себя фрагменты кода, которые могут меняться от использования к использованию. Для примера, абстрагируем цикл от 0 до n на C:
// абстракция цикла
void each(int n, void (*callback)(int, void*), void* closure_data) {
  if(n <= 0) { return; }
  for(int i = 0; i < n; i++) {
    (*callback)(n, closure_data);
  }
}

// колбэк - тело цикла, вариант 1
void cb_body1(int i, void* _) {
  printf("%d", i);
}

// колбэк - тело цикла, вариант 2
void cb_body2(int i, void* acc) {
  int* normalized_acc = (int*)acc;
  *normalized_acc += i;
}

int main() {
  each(10, cb_body1, null); // напечатает строки 0, 1, ...9

  int result = 0;
  each(10, cb_body2, &result); // посчитает в result сумму чисел от 0 до 9
  printf("%d", result);
  return 0;
}

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

Так же стоит заметить, что во многих высокоуровневых языках наряду с обратными вызовами используется механизм замыканий, который позволяет объявлять функции внутри других функций и захватывать окружающие переменные. Но нужно понимать, что это лишь компиляторный сахар, и на самом деле в функцию просто передаются указатели на захваченные переменные в качестве аргументов, подобно тому, как я сделал это руками в примере выше, с помощью аргумента closure_data в функции each. Обычно компилятор создает для этого анонимные структуры (C++, Rust) или анонимные классы (C#), которые хранят указатель на функцию и указатели на окружение. А в некоторых языках, например в js, замыкания возведены в абсолют, и каждая функция является замыканием.
Ответ написан
Maksclub
@Maksclub
maksfedorov.ru
Некоторые случаи использования коллбека (помимо асинхронного упомянутого использования):

В коде: отложенный (ленивый) вызов.
Например есть некий контейнер, в него мы регистрируем некие объекты с некоторой логикой.
Но так как очень много таких кандидатов и они все запускаются, замедляя и работу и нагружая ресурсы, то мы бы хотели, чтобы контейнер просто знал о них, но при инициализации не запускал весь код создания этих объектов. На помощь приходят коллбеки — в коллбеке мы описываем логику создания объекта и (внимание) регистрируем именно коллбек с этой логикой создания, все — это очень быстро и легко, тк не наплодили объектов. Далее только при вызове нужного объекта контейнер видит, что зареган коллбек и вызывает его, тем самым инициализирует создание нужного объекта, описанное в этом коллбеке! ПРОФИТ!

В коде: рекурсивно применить некоторый функционал к элементам коллекции.
Очень популярное использование в Java в стримах.
Есть коллекция элементов, запускаем некий map(), reduce(), filter(). walk() по набору элементов (коллекции) передавая в этот обход коллбек, и ожидаем, что получим результирующий набор после применения коллбека к каждому элементу. То есть этот коллбек будет выполнени внутри обхода, сама конструкция этих методов подразумевает, что вы передадите что-то что потом вызовется.

Между системами: асинхронное взаимодействие
Hook, callback
Есть программа, которая ждет событий от внешней системы. Например есть платежная система Яндекс.Касса и есть ваш магазин. Вы отправили клиента на оплату в платежку, но он ушел "в путешествие" и вы не можете узнать судьбу платежа сразу. Вы можете бомбить сайт платежки, проверяя статус по номеру транзакции, а можете дождаться обратного вызова (коллбека, хука) от платежной системы с событием "Оплатил" или "Не оплатил, тк не хватило".
Также в др системах — само оповестит, вызвав обратно уже меня.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
Griboks
@Griboks
Когда функция выполняется долго, нет смысла ожидать её завершения (визуально это будет выглядеть как зависший браузер, и пользователь закроет сайт). Поэтому ей передают callback, мол, сама сообщишь, когда закончишь работу.
Ответ написан
andreydobrin
@andreydobrin
Сложно , но это пока
Все очень просто:
Вы правильно сказали, что это функция, передающаяся как аргумент в другую функцию:
пример с js
function  first(callbak){
----здесь пишем код функции----
---- здесь можно записать код "функции обратного вызова" 
и она сработает тогда, когда выполнится функция first()----
}

Простым языком - есть одна функция и у нее в параметре другая. Сперва выполнится сама функция, а потом та, которая является аргументом этой функции.
Ответ написан
@AlexSku
Программист по автоматике
Я применял в Direct Show (обработка видео). Есть сторонний поток, который пропускает через себя кадры. Главная программа может постоянно его опрашивать, не появился ли новый кадр. Но зачем тратить время на опросы, когда они только редко будут возвращать положительный результат? Поэтому главная программа просто передаёт ссылку на свой обработчик (функция обратного вызова), а поток, пропускающий видео будет её вызывать всегда в нужное время (желательно, чтобы обработчик успевал всё сделать быстро).
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы