Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Callback-функція». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Callback-функція, це функція, передана як аргумент іншій функції, щоб виконатися пізніше: після того, як станеться подія або завершиться операція.** Простими словами: «я передаю тобі функцію, виклич її, коли будеш готовий». Це можливо тому, що в JavaScript функції є об'єктами першого класу, тож їх можна передавати як звичайні значення. Приймальна функція не викликає callback одразу, а зберігає його і смикає в потрібний момент: коли спрацював таймер, завершився запит або користувач клікнув. На цьому побудовані `setTimeout`, `addEventListener`, `fetch().then()` і майже вся асинхронність. Головна проблема, це глибока вкладеність, відома як callback hell, від якої рятують `Promise` та `async/await`. ```javascript function greet(callback) { console.log('Getting ready to say hello...'); callback('Oleh'); } greet((name) => console.log(`Hello, ${name}!`)); ``` **Ключове:** callback, це функція-аргумент, яку викликають пізніше, коли настане потрібний момент.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**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`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.