Event Loop + Microtasks
JavaScript's event loop manages asynchronous operations and determines the execution order of code.
Call Stack and Event Loop
javascript// Call stack example function first() { console.log('First function'); second(); console.log('First function end'); } function second() { console.log('Second function'); third(); console.log('Second function end'); } function third() { console.log('Third function'); } first(); // Output: // First function // Second function // Third function // Second function end // First function end
Macrotasks vs Microtasks
javascript// Execution order demonstration console.log('1: Synchronous'); setTimeout(() => console.log('2: setTimeout (macrotask)'), 0); Promise.resolve().then(() => console.log('3: Promise (microtask)')); queueMicrotask(() => console.log('4: queueMicrotask')); console.log('5: Synchronous'); // Output order: // 1: Synchronous // 5: Synchronous // 3: Promise (microtask) // 4: queueMicrotask // 2: setTimeout (macrotask)
Microtask Queue
javascript// Microtasks have higher priority than macrotasks setTimeout(() => console.log('Timeout 1'), 0); setTimeout(() => console.log('Timeout 2'), 0); Promise.resolve().then(() => { console.log('Promise 1'); return Promise.resolve(); }).then(() => { console.log('Promise 2'); }); Promise.resolve().then(() => { console.log('Promise 3'); queueMicrotask(() => console.log('Nested microtask')); }); // Output: // Promise 1 // Promise 3 // Promise 2 // Nested microtask // Timeout 1 // Timeout 2
Common Macrotasks and Microtasks
javascript// Macrotasks (Task Queue) setTimeout(() => {}, 0); // Timer setInterval(() => {}, 1000); // Timer setImmediate(() => {}); // Node.js only // Microtasks (Microtask Queue) Promise.resolve().then(() => {}); // Promise queueMicrotask(() => {}); // Direct microtask async function example() { // async/await await somePromise; } // DOM events are also macrotasks button.addEventListener('click', () => { console.log('Click handler (macrotask)'); });
Practical Examples
javascript// Understanding async behavior function demonstrateEventLoop() { console.log('Start'); setTimeout(() => { console.log('Timeout 1'); Promise.resolve().then(() => console.log('Promise in timeout')); }, 0); Promise.resolve().then(() => { console.log('Promise 1'); setTimeout(() => console.log('Timeout in promise'), 0); }); console.log('End'); } demonstrateEventLoop(); // Output: // Start // End // Promise 1 // Timeout 1 // Promise in timeout // Timeout in promise // Avoiding blocking the event loop function heavyTask() { const start = Date.now(); while (Date.now() - start < 1000) { // Blocking operation for 1 second } console.log('Heavy task completed'); } // Bad: Blocks the event loop // heavyTask(); // Good: Break into smaller chunks function nonBlockingHeavyTask(iterations = 1000000) { let i = 0; function processChunk() { const chunkSize = 10000; const end = Math.min(i + chunkSize, iterations); while (i < end) { // Do some work i++; } if (i < iterations) { setTimeout(processChunk, 0); // Continue in next macrotask } else { console.log('Non-blocking task completed'); } } processChunk(); } // Race condition example let counter = 0; function incrementAsync() { setTimeout(() => { counter++; console.log('Counter:', counter); }, 0); } // These will run in unpredictable order incrementAsync(); incrementAsync(); incrementAsync(); // Better approach with promises function incrementAsyncPromise() { return new Promise(resolve => { setTimeout(() => { counter++; console.log('Counter:', counter); resolve(counter); }, 0); }); } // Sequential execution async function incrementSequentially() { await incrementAsyncPromise(); await incrementAsyncPromise(); await incrementAsyncPromise(); }
Event Loop Visualization
javascript// Step-by-step execution example function eventLoopDemo() { console.log('1: Script start'); setTimeout(() => console.log('2: setTimeout'), 0); Promise.resolve() .then(() => console.log('3: Promise 1')) .then(() => console.log('4: Promise 2')); queueMicrotask(() => { console.log('5: queueMicrotask'); queueMicrotask(() => console.log('6: nested queueMicrotask')); }); console.log('7: Script end'); } eventLoopDemo(); // Execution phases: // 1. Synchronous code: 1, 7 // 2. Microtasks: 3, 5, 4, 6 // 3. Macrotasks: 2 // Performance monitoring function measureEventLoopLag() { let start = performance.now(); setTimeout(() => { const lag = performance.now() - start; console.log(`Event loop lag: ${lag.toFixed(2)}ms`); }, 0); } // Monitor continuously function monitorEventLoop() { setInterval(() => { measureEventLoopLag(); }, 1000); }