Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Синхронний та асинхронний callback». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Синхронний callback виконується одразу, під час виклику основної функції і в тому самому стеку викликів, а асинхронний потрапляє в чергу і виконується пізніше, коли весь поточний код завершився і call stack звільнився.** Тому `array.map(fn)` спрацює на місці, а `setTimeout(fn, 0)` навіть з нульовою затримкою виконається після решти синхронного коду. ```javascript function process(callback) { console.log('Before the callback'); callback(); // runs immediately console.log('After the callback'); } process(() => console.log('Synchronous callback')); // Before the callback / Synchronous callback / After the callback setTimeout(() => console.log('Asynchronous callback'), 0); console.log('Sync code'); // Sync code / Asynchronous callback ``` **Ключове:** синхронний callback блокує виконання і завершується до наступного рядка, асинхронний чекає на порожній стек і виконується через event loop.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Синхронний callback виконується одразу під час виклику основної функції, у тому самому стеку викликів, а асинхронний виконується пізніше, вже після завершення поточного коду, через event loop.** Різниця не в синтаксисі колбека, а в тому, коли саме функція, що його отримала, вирішує його викликати. ## Теорія ### TL;DR - Синхронний callback виконується негайно, до завершення поточної функції, у тому самому call stack. - Асинхронний callback ставиться в чергу і виконується після того, як стек звільниться. - Приклади синхронних: `array.map(fn)`, `forEach`, `sort`, `JSON.parse` з reviver. - Приклади асинхронних: `setTimeout(fn, 0)`, `fetch().then(fn)`, обробники подій. - `setTimeout(fn, 0)` не означає «зараз», він означає «якнайшвидше, але після всього синхронного коду». ### Швидкий приклад ```javascript function process(callback) { console.log('Before the callback'); callback(); // runs immediately console.log('After the callback'); } process(() => console.log('Synchronous callback')); ``` Вивід: ```text Before the callback Synchronous callback After the callback ``` Усе виконується по порядку, без затримок. ### Синхронний callback Синхронний callback виконується одразу, під час виклику основної функції, тобто в тому самому стеку викликів, ще до того як поточна функція завершиться. Він блокує подальше виконання: наступний рядок не почнеться, доки колбек не відпрацює. ```javascript const numbers = [1, 2, 3]; const doubled = numbers.map(n => { console.log('processing', n); // runs on every element, right now return n * 2; }); console.log(doubled); // [2, 4, 6] is already available on this line ``` Саме тому результат `map` доступний одразу після виклику: колбек не «планується», він просто викликається. ### Асинхронний callback Асинхронний callback викликається пізніше, після завершення поточного коду: за таймером, після запиту, після події. Він потрапляє в чергу задач, а event loop візьме його лише тоді, коли call stack буде порожній. ```javascript function processAsync(callback) { console.log('Before the callback'); setTimeout(callback, 0); // will run later console.log('After the callback'); } processAsync(() => console.log('Asynchronous callback')); ``` Вивід: ```text Before the callback After the callback Asynchronous callback ``` Колбек виконується не одразу, а після того, як стек викликів звільниться, навіть якщо затримка дорівнює нулю. ### Порівняння | Тип | Коли виконується | Приклад | | --- | --- | --- | | **Синхронний** | Одразу, під час виклику | `array.map(fn)` | | **Асинхронний** | Пізніше, після основного коду | `setTimeout(fn, 0)`, `fetch().then(fn)` | ### Черга мікрозадач і макрозадач Серед асинхронних колбеків теж є порядок. Колбеки Promise потрапляють у чергу мікрозадач, яку event loop спустошує одразу після поточного синхронного коду, а `setTimeout` дає макрозадачу і чекає наступної ітерації циклу. ```javascript console.log('1 sync'); setTimeout(() => console.log('4 macrotask'), 0); Promise.resolve().then(() => console.log('3 microtask')); console.log('2 sync'); // order: 1 sync, 2 sync, 3 microtask, 4 macrotask ``` ### Типові помилки - Читати результат асинхронної операції одразу після виклику функції: там ще `undefined`, бо колбек не встиг виконатися. - Вважати, що `setTimeout(fn, 0)` виконає функцію негайно: вона чекає на порожній call stack. - Ловити помилку з асинхронного колбека зовнішнім `try/catch`: коли колбек виконується, той блок уже завершився. - Ставити `return` у колбеку `forEach` і сподіватися, що це поверне значення із зовнішньої функції: `forEach` ігнорує результат. - Блокувати потік важким синхронним колбеком у циклі: сторінка перестає реагувати, бо стек не звільняється. - Плутати чергу мікрозадач і макрозадач: `Promise.then` завжди випередить `setTimeout(..., 0)`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.