Sincrónico vs. asincrónico: funciones de devolución de llamada, Promesas y async/await
Al finalizar este tema
Podrás explicar la diferencia entre lo sincrónico y lo asincrónico, y comprenderás la evolución desde las funciones de devolución de llamada hasta las Promesas y async/await.
Sincrónico: ejecución secuencial, línea por línea
Sincrónico (Synchronous) es un modo de ejecución del código que se procesa de arriba hacia abajo, una línea a la vez. La siguiente tarea solo comienza después de que la tarea anterior haya finalizado.
console.log("1. Pedido recibido");
console.log("2. Preparación del café (tarda 3 minutos)");
console.log("3. Entrega del café");
// Se ejecuta en orden de 1 → 2 → 3Es intuitivo, pero tiene problemas. Mientras se prepara el café, no se puede hacer nada más. Si la lectura de un archivo tarda 5 segundos, el servidor se bloquea durante ese tiempo; si una consulta a la base de datos tarda 2 segundos, no puede procesar las solicitudes de otros usuarios durante ese tiempo.
Asíncrono: continuar sin esperar
Asíncrono (Asynchronous) significa iniciar una tarea que lleva tiempo y ejecutar el siguiente código sin esperar a que finalice. Cuando la tarea se completa, se recibe el resultado más tarde.
const fs = require("fs");
console.log("1. Inicio de lectura del archivo");
// Asíncrono — inicia la lectura del archivo y pasa inmediatamente al siguiente
fs.readFile("data.txt", "utf8", (err, data) => {
console.log("3. Lectura del archivo completada:", data);
});
console.log("2. Continuando con la siguiente tarea");
// Orden de salida:
// 1. Inicio de la lectura del archivo
// 2. Continuando con la siguiente tarea ← ¡Se ejecuta primero sin esperar!
// 3. Lectura de archivo completada: (contenido del archivo)El orden de salida no es 1 → 2 → 3, sino 1 → 2 → 3. Aunque los números parecen iguales, la operación 2 se ejecuta antes que la 3. Esto ocurre porque no se espera a que finalice la lectura del archivo.
Callbacks: el primer enfoque para la asincronía
En el código anterior, la sección (err, data) => { ... } es una función callback. Significa "llama a esta función cuando termine la tarea".
El problema surge cuando se necesitan operaciones asíncronas en secuencia:
// Infierno de callbacks
fs.readFile("a.txt", "utf8", (err, a) => {
fs.readFile("b.txt", "utf8", (err, b) => {
fs.readFile("c.txt", "utf8", (err, c) => {
console.log(a + b + c);
// La sangría continúa profundizándose...
});
});
});Cuando se anidan varios callbacks, el código se vuelve difícil de leer. Esto se conoce como infierno de callbacks.
Promise: la solución al infierno de callbacks
Promise es una "promesa de proporcionar un resultado en el futuro". Al encadenar con .then(), se pueden procesar las operaciones de forma secuencial sin incurrir en el infierno de callbacks.
const fs = require("fs").promises;
fs.readFile("a.txt", "utf8")
.then(a => {
console.log("Lectura de 'a' completada");
return fs.readFile("b.txt", "utf8");
})
.then(b => {
console.log("Lectura de 'b' completada");
return fs.readFile("c.txt", "utf8");
})
.then(c => {
console.log("Lectura de 'c' completada");
})
.catch(err => {
console.error("Error ocurrido:", err.message);
});La sangría no se incrementa y el manejo de errores con .catch() se centraliza.
async/await: Asincronía con sintaxis síncrona
async/await es una sintaxis que simplifica el uso de Promises y facilita su lectura. Permite que el código asíncrono se lea de arriba hacia abajo, como si fuera código síncrono.
const fs = require("fs").promises;
async function readAll() {
try {
const a = await fs.readFile("a.txt", "utf8");
const b = await fs.readFile("b.txt", "utf8");
const c = await fs.readFile("c.txt", "utf8");
console.log(a + b + c);
} catch (err) {
console.error("Error:", err.message);
}
}
readAll();await significa "espera hasta que termine esta tarea", pero no detiene todo el programa; simplemente pausa temporalmente la ejecución de esta función mientras otras tareas continúan. Para usar await, debes agregar async a la función.
En JavaScript moderno, casi siempre se utiliza async/await. Al solicitar código asíncrono a una IA, pedir que lo escriba "con async/await" suele producir el código más legible.
→ Aplicación en bio: DevBench — Ajax y Fetch