Skip to main content

Callback-функція

Callback-функція, це функція, передана як аргумент іншій функції, щоб виконатися пізніше, після того як станеться якась подія або завершиться операція. Простіше кажучи: «я передаю тобі функцію, виклич її, коли будеш готовий».

Теорія

TL;DR

  • Callback, це функція-аргумент, яку приймальна функція викликає в потрібний момент.
  • Це можливо, бо функції в JavaScript є об'єктами першого класу і передаються як значення.
  • Callback може бути іменованим або анонімним, зокрема стрілковим.
  • Callback не обов'язково асинхронний: array.map(fn) викликає його синхронно, setTimeout(fn), ні.
  • На колбеках побудовані setTimeout, addEventListener, fetch().then().
  • Глибока вкладеність колбеків називається callback hell, її лікують Promise і async/await.

Швидкий приклад

javascript
function sayHello(name) { console.log(`Hello, ${name}!`); } function greet(callback) { console.log('Getting ready to say hello...'); callback('Oleh'); } greet(sayHello); // Output: // Getting ready to say hello... // Hello, Oleh!

Що відбувається:

  1. sayHello, це callback, переданий у greet;
  2. greet викликає його всередині себе;
  3. у консоль виводяться два рядки, у тому порядку, в якому виконується код.

Зверніть увагу: у greet передається sayHello без дужок. greet(sayHello()) викликало б функцію одразу і передало б її результат, тобто undefined.

Як це працює

  • JavaScript приймає callback як значення, адже функції тут є об'єктами першого класу.
  • Приймальна функція не викликає його одразу, а зберігає для подальшого виклику.
  • Коли настає потрібний момент (спрацював таймер, завершився запит, сталася подія), рушій викликає цю функцію.

Callback не зобов'язаний бути іменованим, часто передають анонімну функцію:

javascript
setTimeout(() => { console.log('Two seconds have passed'); }, 2000);

Тут () => console.log(...), це callback-функція, і вона буде викликана через дві секунди, а не одразу.

Callback у реальних ситуаціях

1. Обробник події. Тут callback викликає браузер, коли користувач клікає:

javascript
button.addEventListener('click', () => { console.log('Button clicked!'); });

2. Завантаження даних. Колбеки .then() викликаються після завершення асинхронного запиту:

javascript
fetch('/user') .then(response => response.json()) .then(data => console.log(data));

3. Крок алгоритму. Callback не обов'язково пов'язаний з асинхронністю, він може бути просто способом підставити свою логіку:

javascript
function calculate(a, b, callback) { const result = a + b; callback(result); } calculate(2, 3, (sum) => { console.log('Result:', sum); });

Проблема callback hell

Якщо колбеків забагато, код стає вкладеним і нечитабельним:

javascript
getUser(id, user => { getPosts(user, posts => { getComments(posts, comments => { console.log('Done!'); }); }); });

Це називають callback hell, «пекло з колбеків»: кожен наступний крок зсуває код праворуч, обробка помилок дублюється на кожному рівні, а послідовність дій стає нечитабельною.

Як позбутися вкладеності

Щоб уникнути пекельних вкладеностей, з'явилися проміси:

javascript
getUser(id) .then(getPosts) .then(getComments) .then(console.log);

А потім async/await, який повертає асинхронному коду вигляд звичайного послідовного:

javascript
const user = await getUser(id); const posts = await getPosts(user); const comments = await getComments(posts); console.log('Done!');

Проста аналогія для співбесіди:

Уявіть, що ви замовляєте піцу і кажете: «Коли приготуєте, зателефонуйте мені». Цей дзвінок і є callback.

Підсумок:

ТермінОпис
Callback-функціяФункція, передана в іншу функцію для виконання пізніше
Коли викликаєтьсяПісля події, завершення операції або за умовою
Приклади використанняsetTimeout, addEventListener, fetch().then()
ПроблемаГлибока вкладеність (callback hell)
Сучасні альтернативиPromise, async/await

Типові помилки

  • Передавати виклик замість функції. setTimeout(fn(), 1000) виконує fn негайно і передає таймеру її результат. Правильно, це setTimeout(fn, 1000).
  • Вважати всі колбеки асинхронними. array.forEach(fn) і array.map(fn) викликають callback синхронно, прямо зараз, і нічого не відкладають.
  • Втрачати this. Звичайна функція як callback отримує власний this. Використовуйте стрілкову функцію або bind.
  • Ігнорувати помилки. У стилі «error-first» перший аргумент, це помилка: (err, data) => { if (err) ... }. Пропустивши її, ви мовчки втрачаєте збої.
  • Викликати callback двічі. Якщо після помилки не зробити return, функція піде далі й викличе callback ще раз, що ламає всю логіку зверху.
  • Будувати глибокі піраміди. Три й більше рівнів вкладеності, це сигнал переписати код на Promise або async/await.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.