Suggest an editImprove this articleRefine the answer for “Synchronous and asynchronous callback”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**A synchronous callback runs immediately, during the call to the main function and in the same call stack, while an asynchronous one is queued and runs later, once all the current code has finished and the call stack is empty.** That is why `array.map(fn)` fires on the spot, whereas `setTimeout(fn, 0)` runs after the rest of the synchronous code even with a zero delay. ```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 ``` **Key point:** a synchronous callback blocks execution and finishes before the next line, an asynchronous one waits for an empty stack and runs through the event loop.Shown above the full answer for quick recall.Answer (EN)Image**A synchronous callback runs immediately during the call to the main function, in the same call stack, while an asynchronous one runs later, after the current code has finished, through the event loop.** The difference is not in the callback syntax but in when the function that received it decides to call it. ## Theory ### TL;DR - A synchronous callback runs immediately, before the current function finishes, in the same call stack. - An asynchronous callback is queued and runs once the stack is empty. - Synchronous examples: `array.map(fn)`, `forEach`, `sort`, `JSON.parse` with a reviver. - Asynchronous examples: `setTimeout(fn, 0)`, `fetch().then(fn)`, event handlers. - `setTimeout(fn, 0)` does not mean "now", it means "as soon as possible, but after all synchronous code". ### Quick example ```javascript function process(callback) { console.log('Before the callback'); callback(); // runs immediately console.log('After the callback'); } process(() => console.log('Synchronous callback')); ``` Output: ```text Before the callback Synchronous callback After the callback ``` Everything runs in order, with no delays. ### The synchronous callback A synchronous callback runs at once, during the call to the main function, that is in the same call stack and before the current function has returned. It blocks further execution: the next line does not start until the callback is done. ```javascript const numbers = [1, 2, 3]; const doubled = numbers.map(n => { console.log('processing', n); // runs for every element, right now return n * 2; }); console.log(doubled); // [2, 4, 6] is already available on this line ``` That is exactly why the result of `map` is available right after the call: the callback is not scheduled, it is simply called. ### The asynchronous callback An asynchronous callback is invoked later, after the current code has finished: on a timer, after a request, after an event. It goes into a task queue, and the event loop picks it up only when the call stack is empty. ```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')); ``` Output: ```text Before the callback After the callback Asynchronous callback ``` The callback does not run immediately, it runs once the call stack has been freed, even when the delay is zero. ### Side by side | Type | When it runs | Example | | --- | --- | --- | | **Synchronous** | Immediately, during the call | `array.map(fn)` | | **Asynchronous** | Later, after the main code | `setTimeout(fn, 0)`, `fetch().then(fn)` | ### The microtask and macrotask queues Asynchronous callbacks have an order of their own too. Promise callbacks land in the microtask queue, which the event loop drains right after the current synchronous code, while `setTimeout` creates a macrotask and waits for the next iteration of the loop. ```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 ``` ### Common mistakes - Reading the result of an asynchronous operation right after the function call: it is still `undefined`, because the callback has not run yet. - Believing that `setTimeout(fn, 0)` runs the function immediately: it waits for an empty call stack. - Catching an error from an asynchronous callback with an outer `try/catch`: by the time the callback runs, that block has already finished. - Writing `return` inside a `forEach` callback and expecting it to return a value from the enclosing function: `forEach` ignores the result. - Blocking the thread with a heavy synchronous callback in a loop: the page stops responding because the stack is never freed. - Confusing the microtask and macrotask queues: `Promise.then` always wins over `setTimeout(..., 0)`.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.