Урок 19: Callback-функции в JavaScript’е

Этот урок очень важен, потому что колбэки лежат в основе асинхронного программирования, работы с событиями и многими API. Давайте начнем!

Что такое callback-функции?

Callback-функция (от англ. callback «обратный вызов») это функция, которая передается в другую функцию как аргумент и вызывается внутри нее. Зачем это нужно? Чтобы контролировать порядок выполнения кода, особенно в асинхронных операциях (например, загрузка данных, таймеры, обработка событий).

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

Примеры использования callback-функций

Давайте разберемся на практике.

Пример 1: setTimeout

Классический пример, функция setTimeout, которая принимает callback и выполняет его через указанное время:

function sayHello() {
  console.log("Привет, Максим!");
}

// sayHello — callback, который выполнится через 2 секунды
setTimeout(sayHello, 2000);

Пример 2: Обработка событий

Callback’и часто используются для реакции на действия пользователя:

const button = document.querySelector('#myButton');

button.addEventListener('click', function() {
  console.log("Кнопка нажата!");
});

Здесь анонимная функция это callback, который сработает при клике.

Пример 3: Асинхронные запросы

Предположим, мы загружаем данные с сервера. Используем callback для обработки результата:

function fetchData(url, callback) {
  // Имитация запроса
  setTimeout(() => {
    const data = { id: 1, name: "Тестовые данные" };
    callback(data);
  }, 1000);
}

fetchData('https://api.example.com', function(data) {
  console.log("Данные получены:", data);
});

Потенциальные проблемы с callback-функциями

Несмотря на мощь, callback’и могут создавать сложности. Разберем основные подводные камни.

1. Callback Hell

Когда колбэки вложены друг в друга, код становится нечитаемым:

fetchData('/users', function(users) {
  fetchData('/posts', function(posts) {
    fetchData('/comments', function(comments) {
      console.log("Все данные загружены:", users, posts, comments);
    });
  });
});

Такая структура напоминает пирамиду, которую сложно поддерживать. Решение, использовать промисы или async/await (о них в следующих уроках).

2. Проблемы с обработкой ошибок

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

fetchData('/users', function(error, data) {
  if (error) {
    console.error("Ошибка:", error);
    return;
  }
  console.log("Данные:", data);
});

Если пропустить проверку if (error), можно получить неожиданные баги.

3. Потеря контекста (this)

Если передать метод объекта как callback, контекст this может потеряться:

const user = {
  name: "Максим",
  greet: function() {
    console.log("Привет, я", this.name);
  }
};

// this.name будет undefined!
setTimeout(user.greet, 1000); 

// Решение: использовать bind, стрелочные функции или обертку
setTimeout(() => user.greet(), 1000);

Практические задачи

Закрепим знания на практике. Решайте задачи по порядку.

Задача 1: Создайте функцию с callback

Напишите функцию calculate(a, b, callback), которая принимает два числа и callback, выполняющий операцию над ними. Пример:

calculate(5, 3, (x, y) => x + y); // Вернет 8
calculate(5, 3, (x, y) => x * y); // Вернет 15

Задача 2: Обработайте событие загрузки изображения

Создайте изображение и используйте callback, чтобы вывести сообщение, когда оно загрузится:

const img = new Image();
img.src = 'photo.jpg';

img.onload = function() {
  console.log("Изображение загружено!");
};

Задача 3: Эмулируйте цепочку асинхронных операций

Напишите код, который последовательно выполняет три асинхронные задачи (например, задержки через setTimeout), выводя сообщения после каждой. Избегайте callback hell.

Заключение

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

Полный курс «JavaScript для начинающих» доступен здесь — https://max-gabov.ru/javascript-dlya-nachinaushih