Callbacks
Un callback es una función que se pasa como argumento a otra función y se ejecuta después de que esa función termine su trabajo. Es el patrón más básico para manejar operaciones asíncronas en JavaScript.
¿Qué es un Callback?
Un callback es simplemente una función que se ejecuta “después” de otra operación:
const callBackButton = document . getElementById ( "callback" );
callBackButton . addEventListener ( "click" , function () {
function saludar ( nombre , callback ) {
console . log ( "Hola " + nombre );
callback ();
}
function despedir () {
console . log ( "Adiós!" );
}
saludar ( "Julián" , despedir );
});
Salida:
Desglose del Ejemplo
saludar acepta dos parámetros
nombre: un string
callback: una función que se ejecutará después
saludar hace su trabajo
Imprime el saludo con el nombre.
saludar ejecuta el callback
Llama a callback(), que ejecuta la función despedir.
Los callbacks son funciones regulares. Lo especial es cuándo y dónde se ejecutan.
Callbacks con Funciones Anónimas
No necesitas definir el callback por separado. Puedes usar una función anónima:
saludar ( "María" , function () {
console . log ( "Hasta luego!" );
});
O con arrow functions (sintaxis moderna):
saludar ( "Carlos" , () => {
console . log ( "¡Nos vemos!" );
});
Callbacks Asíncronos
Los callbacks realmente brillan con operaciones asíncronas como setTimeout:
function mostrarMensaje ( mensaje , callback ) {
setTimeout (() => {
console . log ( mensaje );
callback ();
}, 2000 );
}
mostrarMensaje ( "Cargando..." , () => {
console . log ( "¡Listo!" );
});
// Salida después de 2 segundos:
// Cargando...
// ¡Listo!
Callbacks con Parámetros
Los callbacks pueden recibir parámetros:
function procesarUsuario ( userId , callback ) {
// Simular obtener datos de usuario
setTimeout (() => {
const usuario = {
id: userId ,
nombre: "Juan" ,
email: "[email protected] "
};
callback ( usuario );
}, 1000 );
}
procesarUsuario ( 123 , ( usuario ) => {
console . log ( "Usuario:" , usuario . nombre );
console . log ( "Email:" , usuario . email );
});
Callbacks para Manejo de Errores
Una convención común es pasar el error como primer parámetro del callback:
function obtenerDatos ( url , callback ) {
setTimeout (() => {
const error = Math . random () > 0.5 ? null : new Error ( "Error de red" );
const datos = error ? null : { resultado: "Datos exitosos" };
callback ( error , datos );
}, 1000 );
}
obtenerDatos ( '/api/users' , ( error , datos ) => {
if ( error ) {
console . error ( 'Hubo un error:' , error . message );
return ;
}
console . log ( 'Datos recibidos:' , datos );
});
Este patrón “error-first callback” es muy común en Node.js y bibliotecas JavaScript.
El Problema: Callback Hell
Cuando necesitas realizar múltiples operaciones asíncronas en secuencia, los callbacks pueden volverse difíciles de manejar:
const hellButton = document . getElementById ( "hell-button" );
hellButton . addEventListener ( "click" , function () {
setTimeout (() => {
console . log ( "Primer paso" );
setTimeout (() => {
console . log ( "Segundo paso" );
setTimeout (() => {
console . log ( "Tercer paso" );
}, 1000 );
}, 1000 );
}, 1000 );
});
Problemas con este código:
Difícil de leer (forma de “pirámide”)
Difícil de mantener
Difícil de manejar errores
Difícil de agregar nuevos pasos
Este patrón se conoce como “Callback Hell” o “Pyramid of Doom” . Es una señal de que necesitas refactorizar tu código.
Un Ejemplo Más Real de Callback Hell
// Ejemplo conceptual (pseudocódigo)
getUser ( userId , function ( user ) {
getOrders ( user , function ( orders ) {
processOrders ( orders , function ( processed ) {
sendEmail ( processed , function ( confirmation ) {
console . log ( "Order Processed:" , confirmation );
});
});
});
});
Cada nivel de indentación hace el código más difícil de seguir.
Buenas Prácticas con Callbacks
1. Usa Funciones con Nombre
En lugar de funciones anónimas anidadas:
// ❌ Mal: Difícil de leer
setTimeout (() => {
console . log ( "Paso 1" );
setTimeout (() => {
console . log ( "Paso 2" );
}, 1000 );
}, 1000 );
// ✅ Mejor: Funciones con nombre
function paso1 () {
console . log ( "Paso 1" );
setTimeout ( paso2 , 1000 );
}
function paso2 () {
console . log ( "Paso 2" );
}
setTimeout ( paso1 , 1000 );
2. Maneja Errores Apropiadamente
function operacionAsincrona ( callback ) {
setTimeout (() => {
try {
// Operación que puede fallar
const resultado = operacionPeligrosa ();
callback ( null , resultado );
} catch ( error ) {
callback ( error , null );
}
}, 1000 );
}
operacionAsincrona (( error , resultado ) => {
if ( error ) {
console . error ( 'Error:' , error );
return ;
}
console . log ( 'Resultado:' , resultado );
});
3. Mantén los Callbacks Simples
// ❌ Mal: Callback con mucha lógica
cargarDatos (( datos ) => {
// 50 líneas de lógica compleja...
});
// ✅ Mejor: Callback llama a una función separada
cargarDatos ( procesarDatos );
function procesarDatos ( datos ) {
// Lógica compleja aquí...
}
Callbacks en Funciones de Array
Los callbacks también se usan en métodos de array:
const numeros = [ 1 , 2 , 3 , 4 , 5 ];
// forEach recibe un callback
numeros . forEach ( function ( numero ) {
console . log ( numero * 2 );
});
// map recibe un callback y retorna un nuevo array
const duplicados = numeros . map ( function ( numero ) {
return numero * 2 ;
});
// filter recibe un callback que retorna true/false
const pares = numeros . filter ( function ( numero ) {
return numero % 2 === 0 ;
});
Cuándo Usar Callbacks
Operaciones asíncronas simples y únicas
Event listeners
Métodos de array (map, filter, forEach)
APIs que solo soportan callbacks
Múltiples operaciones asíncronas en secuencia
Lógica compleja de manejo de errores
Cuando necesitas coordinar múltiples operaciones asíncronas
En código moderno (usa Promises o async/await en su lugar)
La Evolución: De Callbacks a Promises
Los callbacks fueron la primera solución para el asincronismo en JavaScript, pero tienen limitaciones. Por eso se crearon las Promises , que resuelven muchos de los problemas de los callbacks.
En código nuevo, prefiere Promises o async/await sobre callbacks anidados. Sin embargo, entender callbacks es fundamental porque:
Muchas APIs aún los usan
Necesitas entenderlos para trabajar con código existente
Son la base para entender Promises y async/await
Próximos Pasos
Promises Aprende cómo Promises mejoran el manejo asíncrono
Async/Await La sintaxis más moderna para código asíncrono