Frontend Interview Guide: How Macro‑ and Micro‑Tasks Determine JavaScript Execution Order
The article explains JavaScript’s single‑threaded event loop, classifies macro‑ and micro‑tasks, details their execution order, and walks through classic and advanced code snippets to show how interview questions about output are solved in typical front‑end interview scenarios.
JavaScript is Single‑Threaded
JS runs on a single main thread; time‑consuming operations are handed to Web APIs and their callbacks are queued for later execution.
Task Classification
Macro Task:
script (the whole script is the first macro task)
setTimeout / setInterval
I/O (Node.js)
requestAnimationFrame
Micro Task:
Promise.then / .catch / .finally
queueMicrotask()
MutationObserver
async/await (code after await)Execution Order Rules
1. Execute the current macro task (e.g., the whole script)
2. Execute all micro‑tasks in the queue (including those added while emptying)
3. Render if needed
4. Take the next macro task and repeat 1‑3In short: after each macro task finishes, the micro‑task queue is emptied immediately.
Classic Interview Example
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => {
console.log('3');
Promise.resolve().then(() => console.log('4')); // micro‑task added inside a micro‑task
});
console.log('5');
// Analysis:
// Synchronous: 1, 5
// Micro‑tasks (cleared): 3, 4 (4 is added during 3 and still cleared this round)
// Macro‑task: 2
// Output: 1, 5, 3, 4, 2The Essence of async/await
async function foo() {
console.log('A');
await bar(); // after bar() finishes, the code after await goes to the micro‑task queue
console.log('C'); // micro‑task
}
async function bar() {
console.log('B');
}
console.log('start');
foo();
console.log('end');
// Output: start, A, B, end, C
// Explanation: await bar() turns the following console.log('C') into a micro‑task, so the synchronous end runs first.Advanced Combined Example
console.log('1');
setTimeout(() => {
console.log('2');
Promise.resolve().then(() => console.log('3'));
}, 0);
Promise.resolve()
.then(() => console.log('4'))
.then(() => console.log('5'));
console.log('6');
// Execution analysis:
// Synchronous: 1, 6
// Micro‑tasks: 4, 5
// Second macro task (setTimeout): 2
// Micro‑task inside that macro task: 3
// Output: 1, 6, 4, 5, 2, 3Solution Method for Interview Questions
Identify synchronous code and list its output order.
Identify all micro‑tasks, then clear the micro‑task queue in the order they were enqueued (including any newly added).
Proceed to the next macro task and repeat steps 2‑3.
Key Takeaways
JS is single‑threaded; the event loop orders asynchronous code.
Micro‑tasks (Promise, queueMicrotask) run before macro‑tasks (setTimeout, setInterval).
Typical solving approach: synchronous → empty micro‑task queue → next macro task, repeat.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
