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

#javascript

#javascript

Вопрос:

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

1 — Использование функций обратного вызова:

     function showArticle(id, callbackSuccess, callbackError){
        
        if (true){
            callbackSuccess("This is a callback function", "It is very utilized.");
        } else {
            callbackError("Error on data recovery.");
        }

    }

    var callbackSuccess = function(title, description){
        document.write("<h1>"   title   "</h1>");
        document.write("<hr>");
        document.write("<p>"   description   "</p>");
    }

    var callbackError = function(error){
        document.write("<p><b>Erro:</b>"   error   "</p>");
    }

    showArticle(1, callbackSuccess, callbackError);
 

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

     function showArticle(id){
        
        if (true){
            callbackSuccess("This is a callback function", "It is very utilized.");
        } else {
            callbackError("Error on data recovery.");
        }

    }

    var callbackSuccess = function(title, description){
        document.write("<h1>"   title   "</h1>");
        document.write("<hr>");
        document.write("<p>"   description   "</p>");
    }

    var callbackError = function(error){
        document.write("<p><b>Erro:</b>"   error   "</p>");
    }

    showArticle(1);
 

Почему я должен использовать функции обратного вызова, а не просто вызывать их в примере 2?

Ответ №1:

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

Обычно используются обратные вызовы:

  1. С помощью функций итерации, сопоставления или фильтрации, которые вызывают ваш обратный вызов для каждого элемента в массиве, списке или другом контейнере
  2. С помощью функций, которые выполняют асинхронную работу, которые вызывают ваш обратный вызов, когда работа успешно завершена, сбой или оба (в зависимости от стиля API, который вы вызываете)
  3. Функции, которые принимают обратные вызовы, будут вызывать, когда или если что-то произойдет, например, обработчик click событий для элемента DOM

… но есть и другие категории.

filter Функция в массивах является примером # 1: она вызывает обратный вызов для каждой записи в массиве, используя возвращаемое значение обратного вызова, чтобы решить, должна ли запись находиться в новом, отфильтрованном массиве, который она возвращает:

 const numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const odds = numbers.filter(num => {
    console.log(`callback called with ${num}`); // logs 10 times
    return num % 2;
});
console.log(odds); // [1, 3, 5, 7, 9] 

Методы Promise then , catch , и finally являются примерами # 2. Предположим, у нас есть startSomethingAsynchronous функция, которая возвращает обещание. Вот как могут быть настроены обработчики выполнения и отклонения (обратные вызовы):

 startSomethingAsynchronous()                // Starts an asynchronous process
.then(result => {                           // <− 
    // ...do something with the result...   //    − This is a fulfillment handler
})                                          // <− 
.catch(error => {                           // <− 
    // ...report or handle error...         //    − This is a rejection handler
});                                         // <− 
 

Обработчик выполнения вызывается, если обещание от startSomethingAsynchronous() выполнено (успешно завершено). Обработчик отклонения вызывается, если это обещание отклонено (сбой), или если это обещание выполнено, но обещание, возвращенное then rejects (например, из-за ошибки в обработчике выполнения). (Объединение подобных вещей в цепочки довольно распространено, но есть много других способов использования promises, это всего лишь один пример.)

addEventListener Функция в DOM является примером # 3:

 document.querySelector("input[type=button]")
    .addEventListener("click", function() {
        console.log("Clicked!"); // logs as many times as you click the button
    }); 
 <input type="button" value="Click Me"> 

Ответ №2:

JavaScript выполняет код последовательно в порядке сверху вниз. Однако в некоторых случаях код выполняется (или должен выполняться) после того, как происходит что-то еще, а также не последовательно. Это называется асинхронным программированием.

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

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

— freecodecamp.org

Вы можете прочитать больше здесь.

Ответ №3:

Приведенные выше ответы верны. Моя — это просто упрощение одной из причин (асинхронный характер)

Обратите внимание, что НЕ все последовательно.

  • Вызов базы данных может занять 100 мс, 200 мс или 1 сек для возврата данных.
  • Чтение файла, размер которого вам неизвестен, может занять X несколько секунд.

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

Некоторые языки блокируют поток (я буду ждать вызова базы данных) или создавать потоки (я буду выполнять эти операции в другом «процессе»)

JS будет содержать обещания и обратные вызовы.