🔄
Intermedio
10 min lecturaEvent Loop y rendimiento asíncrono
Optimiza operaciones asíncronas y comprende el event loop
Comprendiendo el Event Loop de JavaScript
El event loop es el mecanismo que permite a JavaScript manejar operaciones asíncronas pese a ser single‑thread. Entender cómo funciona es clave para escribir código rápido.
Fases del Event Loop
- Call Stack: Ejecuta código síncrono
- Cola de microtareas: Promesas, queueMicrotask, MutationObserver
- Cola de macrotareas: setTimeout, setInterval, operaciones de I/O
- Cola de render: requestAnimationFrame, render del navegador
Microtareas vs macrotareas
Comprender la diferencia entre microtareas y macrotareas es esencial para optimizar:
// ❌ Bad: Blocking the event loop with long synchronous operations
function processLargeArray(arr) {
arr.forEach(item => {
// Complex synchronous operation
complexCalculation(item);
});
}
processLargeArray(hugeArray); // Blocks UI for too long
// ✅ Good: Break work into chunks using microtasks
async function processLargeArrayOptimized(arr) {
const chunkSize = 100;
for (let i = 0; i < arr.length; i += chunkSize) {
const chunk = arr.slice(i, i + chunkSize);
chunk.forEach(item => complexCalculation(item));
// Allow other tasks to run
await new Promise(resolve => setTimeout(resolve, 0));
}
}
// ✅ Even better: Use requestIdleCallback for non-critical work
function processWithIdleCallback(arr) {
let index = 0;
function processChunk(deadline) {
while (deadline.timeRemaining() > 0 && index < arr.length) {
complexCalculation(arr[index++]);
}
if (index < arr.length) {
requestIdleCallback(processChunk);
}
}
requestIdleCallback(processChunk);
}
Optimización de Promesas
Optimiza cadenas de Promises y operaciones async:
// ❌ Bad: Sequential Promise execution
async function fetchAllData() {
const user = await fetchUser();
const posts = await fetchPosts();
const comments = await fetchComments();
return { user, posts, comments };
}
// ✅ Good: Parallel Promise execution
async function fetchAllDataOptimized() {
const [user, posts, comments] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
]);
return { user, posts, comments };
}
// ✅ Good: Handle partial failures gracefully
async function fetchWithFallback() {
const results = await Promise.allSettled([
fetchUser(),
fetchPosts(),
fetchComments()
]);
return results.map(result =>
result.status === 'fulfilled' ? result.value : null
);
}
Evitar bloquear el event loop
// ❌ Bad: Long-running synchronous loop
function calculateFibonacci(n) {
if (n <= 1) return n;
return calculateFibonacci(n - 1) + calculateFibonacci(n - 2);
}
// ✅ Good: Break into smaller tasks
async function calculateFibonacciOptimized(n, memo = {}) {
if (n <= 1) return n;
if (memo[n]) return memo[n];
// Yield to event loop periodically
if (n % 10 === 0) {
await new Promise(resolve => setTimeout(resolve, 0));
}
memo[n] = await calculateFibonacciOptimized(n - 1, memo) +
await calculateFibonacciOptimized(n - 2, memo);
return memo[n];
}
// ✅ Best: Use Web Workers for CPU-intensive tasks
const worker = new Worker('fibonacci-worker.js');
worker.postMessage({ n: 40 });
worker.onmessage = (e) => console.log('Result:', e.data);
Planificación de microtareas
// Different ways to schedule tasks
console.log('1: Synchronous');
setTimeout(() => console.log('2: Macrotask (setTimeout)'), 0);
Promise.resolve().then(() => console.log('3: Microtask (Promise)'));
queueMicrotask(() => console.log('4: Microtask (queueMicrotask)'));
console.log('5: Synchronous');
// Output order:
// 1: Synchronous
// 5: Synchronous
// 3: Microtask (Promise)
// 4: Microtask (queueMicrotask)
// 2: Macrotask (setTimeout)
Buenas prácticas
- Usa
Promise.all()para operaciones async en paralelo - Divide tareas largas en chunks con
setTimeoutorequestIdleCallback - Prioriza tareas críticas con microtareas (Promises)
- Difiere trabajo no crítico con macrotareas (setTimeout)
- Usa Web Workers para cálculos intensivos de CPU
- Evita cadenas de Promises profundamente anidadas: usa async/await
- Monitorea el lag del event loop con
performance.now() - Usa
Promise.race()para patrones de timeout