JavaScript
Tutorial JavaScript: Callbacks
JavaScript y uso de funciones de orden superior para asincronía. Aprende a manejar callbacks y mejorar flujo de control en programación asíncrona.
Aprende JavaScript y certifícateFunciones de orden superior: Fundamentos de la programación funcional aplicados a la asincronía
Las funciones de orden superior son uno de los pilares fundamentales de la programación funcional en JavaScript. Se trata de funciones que pueden recibir otras funciones como argumentos o devolverlas como resultado. Este concepto es crucial para entender cómo JavaScript maneja la asincronía mediante callbacks.
En JavaScript, las funciones son ciudadanos de primera clase, lo que significa que pueden ser tratadas como cualquier otro valor: asignadas a variables, pasadas como argumentos o devueltas por otras funciones. Esta característica es la que permite implementar patrones asíncronos mediante callbacks.
Funciones como valores
Antes de profundizar en la asincronía, es importante entender cómo JavaScript trata las funciones como valores:
// Asignar una función a una variable
const saludar = function(nombre) {
return `Hola, ${nombre}!`;
};
// Pasar una función como argumento
function ejecutarFuncion(fn, valor) {
return fn(valor);
}
const resultado = ejecutarFuncion(saludar, "María");
console.log(resultado); // "Hola, María!"
Esta capacidad de manipular funciones como valores es lo que nos permite implementar callbacks para operaciones asíncronas.
Funciones que devuelven funciones
Otro concepto clave es la capacidad de crear funciones que devuelven otras funciones:
function multiplicadorPor(factor) {
// Devuelve una nueva función
return function(numero) {
return numero * factor;
};
}
const duplicar = multiplicadorPor(2);
const triplicar = multiplicadorPor(3);
console.log(duplicar(5)); // 10
console.log(triplicar(5)); // 15
Este patrón es especialmente útil para crear funciones especializadas que pueden utilizarse en contextos asíncronos.
Aplicando funciones de orden superior a la asincronía
En JavaScript, las operaciones asíncronas como lecturas de archivos, peticiones de red o temporizadores utilizan callbacks para manejar resultados que no están disponibles inmediatamente. Veamos cómo las funciones de orden superior facilitan este patrón:
function realizarOperacionAsincrona(datos, callback) {
// Simulamos una operación asíncrona con setTimeout
setTimeout(() => {
const resultado = datos.toUpperCase();
callback(resultado);
}, 1000);
}
realizarOperacionAsincrona("datos procesados", resultado => {
console.log(resultado); // "DATOS PROCESADOS"
});
En este ejemplo, realizarOperacionAsincrona
es una función de orden superior que acepta datos y una función callback. La operación se ejecuta de forma asíncrona (simulada con setTimeout
), y cuando finaliza, invoca al callback con el resultado.
Composición de operaciones asíncronas
Las funciones de orden superior nos permiten componer operaciones asíncronas, encadenando callbacks para realizar secuencias de operaciones:
function obtenerDatos(id, callback) {
setTimeout(() => {
const datos = { id, nombre: "Producto ejemplo" };
callback(datos);
}, 1000);
}
function procesarDatos(datos, callback) {
setTimeout(() => {
const procesado = { ...datos, procesado: true };
callback(procesado);
}, 1000);
}
// Composición de operaciones asíncronas
obtenerDatos(123, datos => {
console.log("Datos obtenidos:", datos);
procesarDatos(datos, resultado => {
console.log("Datos procesados:", resultado);
});
});
Esta capacidad de composición es fundamental, aunque como veremos en secciones posteriores, puede llevar a problemas de legibilidad cuando se anidan demasiados callbacks.
Transformación de operaciones síncronas en asíncronas
Las funciones de orden superior también nos permiten transformar operaciones síncronas en asíncronas:
function hacerAsincrono(fn) {
return function(...args) {
const callback = args.pop();
setTimeout(() => {
try {
const resultado = fn(...args);
callback(null, resultado);
} catch (error) {
callback(error);
}
}, 0);
};
}
// Función síncrona
function sumar(a, b) {
return a + b;
}
// Versión asíncrona
const sumarAsincrono = hacerAsincrono(sumar);
sumarAsincrono(5, 3, (error, resultado) => {
if (error) {
console.error("Error:", error);
return;
}
console.log("Resultado:", resultado); // 8
});
En este ejemplo, hacerAsincrono
es una función de orden superior que transforma cualquier función síncrona en una versión asíncrona que utiliza callbacks.
Funciones de orden superior para control de flujo asíncrono
Podemos crear funciones de orden superior que nos ayuden a controlar el flujo de operaciones asíncronas:
function serie(tareas, finalCallback) {
const resultados = [];
let indiceActual = 0;
function siguienteTarea() {
if (indiceActual === tareas.length) {
finalCallback(null, resultados);
return;
}
tareas[indiceActual]((error, resultado) => {
if (error) {
finalCallback(error);
return;
}
resultados.push(resultado);
indiceActual++;
siguienteTarea();
});
}
siguienteTarea();
}
// Ejemplo de uso
const tarea1 = callback => setTimeout(() => callback(null, "Resultado 1"), 1000);
const tarea2 = callback => setTimeout(() => callback(null, "Resultado 2"), 500);
serie([tarea1, tarea2], (error, resultados) => {
if (error) {
console.error("Error:", error);
return;
}
console.log("Resultados:", resultados); // ["Resultado 1", "Resultado 2"]
});
Esta función serie
ejecuta una lista de tareas asíncronas en secuencia, recopilando sus resultados. Es un ejemplo de cómo las funciones de orden superior pueden ayudarnos a abstraer patrones complejos de control de flujo asíncrono.
Closures en callbacks asíncronos
Los closures (cierres) son fundamentales para mantener el contexto en operaciones asíncronas. Un closure permite a una función acceder a variables de su ámbito exterior incluso después de que la función externa haya terminado de ejecutarse:
function crearContadorAsincrono() {
let contador = 0;
return function incrementar(callback) {
setTimeout(() => {
contador++;
callback(contador);
}, 1000);
};
}
const incrementarContador = crearContadorAsincrono();
incrementarContador(valor => console.log(valor)); // 1
incrementarContador(valor => console.log(valor)); // 2
incrementarContador(valor => console.log(valor)); // 3
En este ejemplo, la función incrementar
mantiene acceso a la variable contador
gracias al closure, incluso cuando se ejecuta de forma asíncrona.
Las funciones de orden superior, combinadas con los conceptos de programación funcional como closures y funciones como valores, proporcionan la base para implementar patrones asíncronos en JavaScript. Estos fundamentos son esenciales para entender no solo los callbacks, sino también las abstracciones más modernas como Promises y async/await que veremos en lecciones posteriores.
Patrones de implementación: Error-first callbacks y convenciones en APIs de Node.js
En el ecosistema de Node.js, los callbacks no se implementan de cualquier manera, sino que siguen patrones y convenciones específicas que facilitan su uso consistente a través de diferentes APIs. El patrón más importante y ampliamente adoptado es el error-first callback (callback con error primero), también conocido como "Node-style callback".
El patrón Error-First Callback
Este patrón establece una convención simple pero poderosa: el primer parámetro de cualquier función callback siempre debe ser un objeto de error (o null
si no hay error), seguido de los resultados de la operación.
function operacionAsincrona(parametros, callback) {
// Realizar operación...
if (/* ocurrió un error */) {
callback(new Error('Descripción del error'));
return;
}
// Operación exitosa
callback(null, resultado);
}
Esta convención ofrece varias ventajas clave:
- Proporciona una forma consistente de manejar errores
- Permite detección temprana de problemas
- Facilita la propagación de errores en operaciones encadenadas
- Establece un contrato claro entre las APIs y sus consumidores
Implementación en APIs nativas de Node.js
Las APIs del núcleo de Node.js siguen rigurosamente este patrón. Veamos algunos ejemplos:
Sistema de archivos (fs)
const fs = require('fs');
fs.readFile('archivo.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error al leer el archivo:', err);
return;
}
console.log('Contenido del archivo:', data);
});
Operaciones de red
const http = require('http');
http.get('http://ejemplo.com', (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log('Respuesta completa:', data);
});
}).on('error', (err) => {
console.error('Error en la petición:', err);
});
Buenas prácticas al implementar error-first callbacks
Cuando diseñes tus propias funciones asíncronas, es recomendable seguir estas prácticas establecidas:
- Consistencia en la firma: Mantén el parámetro de error siempre como primer argumento.
// ✅ Correcto
function buscarUsuario(id, callback) {
// Implementación...
callback(null, usuario);
}
// ❌ Incorrecto
function buscarUsuario(id, callback) {
// Implementación...
callback(usuario, null); // Error como segundo parámetro
}
- Manejo explícito de errores: Siempre verifica el error antes de procesar resultados.
buscarUsuario(123, (err, usuario) => {
if (err) {
// Manejar el error primero
console.error('Error:', err);
return;
}
// Procesar el resultado solo si no hay error
console.log('Usuario encontrado:', usuario);
});
- Errores informativos: Usa objetos
Error
con mensajes descriptivos.
function validarDatos(datos, callback) {
if (!datos.nombre) {
callback(new Error('El nombre es obligatorio'));
return;
}
// Continuar con la validación...
callback(null, true);
}
- Retorno temprano: Después de invocar el callback con un error, usa
return
para evitar ejecución adicional.
function procesarPago(monto, callback) {
if (monto <= 0) {
callback(new Error('El monto debe ser positivo'));
return; // Importante: evita ejecución adicional
}
// Continuar con el procesamiento...
}
Tipos de errores en Node.js
Node.js proporciona varias clases de error que puedes utilizar para ser más específico:
// Error genérico
callback(new Error('Mensaje de error'));
// Error específico para operaciones de red
callback(new TypeError('El parámetro debe ser una cadena'));
// Error personalizado
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
callback(new ValidationError('Datos inválidos'));
Propagación de errores en cadenas de callbacks
Una ventaja del patrón error-first es la facilidad para propagar errores a través de múltiples operaciones asíncronas:
function procesarArchivo(ruta, callback) {
fs.readFile(ruta, 'utf8', (err, contenido) => {
if (err) {
callback(err); // Propaga el error hacia arriba
return;
}
try {
const datos = JSON.parse(contenido);
procesarDatos(datos, callback); // Pasa el mismo callback
} catch (error) {
callback(new Error(`Error al parsear JSON: ${error.message}`));
}
});
}
function procesarDatos(datos, callback) {
// Procesamiento...
if (/* error durante procesamiento */) {
callback(new Error('Error en procesamiento'));
return;
}
callback(null, resultadoFinal);
}
Convenciones adicionales en APIs de Node.js
Además del patrón error-first, las APIs de Node.js siguen otras convenciones importantes:
- Opciones como objeto: Muchas funciones aceptan un objeto de opciones para configuración.
fs.readFile('archivo.txt', {
encoding: 'utf8',
flag: 'r'
}, (err, data) => {
// Manejo de resultado
});
- Callbacks opcionales: Algunas APIs permiten omitir el callback, devolviendo una Promise en su lugar (en versiones recientes).
// Con callback
fs.readFile('archivo.txt', (err, data) => {
// Manejo de resultado
});
// Con promesas (Node.js moderno)
const { promises: fsPromises } = require('fs');
fsPromises.readFile('archivo.txt')
.then(data => console.log(data))
.catch(err => console.error(err));
- Métodos síncronos con sufijo 'Sync': Para operaciones que tienen versiones síncronas y asíncronas.
// Versión asíncrona con callback
fs.readFile('archivo.txt', (err, data) => {
// Manejo asíncrono
});
// Versión síncrona (bloqueante)
try {
const data = fs.readFileSync('archivo.txt');
console.log(data);
} catch (err) {
console.error(err);
}
Implementación de funciones que siguen el patrón error-first
Cuando crees tus propias funciones asíncronas, puedes seguir este patrón básico:
function miOperacionAsincrona(parametro1, parametro2, callback) {
// Validación de parámetros
if (!parametro1) {
process.nextTick(() => {
callback(new Error('Parámetro 1 es requerido'));
});
return;
}
// Simulación de operación asíncrona
setTimeout(() => {
try {
const resultado = /* cálculo que podría fallar */;
callback(null, resultado);
} catch (error) {
callback(error);
}
}, 100);
}
El uso de process.nextTick()
asegura que el callback se ejecute de forma asíncrona incluso cuando detectamos errores inmediatamente, manteniendo un comportamiento consistente.
Manejo de múltiples resultados
Cuando necesitas devolver múltiples valores, simplemente añades más parámetros después del error:
function obtenerEstadisticas(archivo, callback) {
fs.stat(archivo, (err, stats) => {
if (err) {
callback(err);
return;
}
const esDirectorio = stats.isDirectory();
const tamaño = stats.size;
const fechaModificacion = stats.mtime;
callback(null, esDirectorio, tamaño, fechaModificacion);
});
}
obtenerEstadisticas('./carpeta', (err, esDir, tamaño, fecha) => {
if (err) {
console.error('Error:', err);
return;
}
console.log(`Es directorio: ${esDir}`);
console.log(`Tamaño: ${tamaño} bytes`);
console.log(`Última modificación: ${fecha}`);
});
El patrón error-first callback se ha convertido en un estándar de facto en el ecosistema de Node.js, proporcionando una forma consistente y predecible de manejar operaciones asíncronas. Aunque las Promises y async/await ofrecen alternativas más modernas, entender este patrón es fundamental para trabajar con el amplio conjunto de APIs y bibliotecas basadas en callbacks.
Limitaciones y problemas: Callback hell y estrategias para mejorar la legibilidad
A pesar de su utilidad, los callbacks presentan desafíos significativos cuando se utilizan en operaciones asíncronas complejas. El más notorio es el llamado "callback hell" (también conocido como "pyramid of doom" o pirámide de la perdición), un problema que afecta directamente a la legibilidad y mantenibilidad del código.
¿Qué es el callback hell?
El callback hell ocurre cuando tenemos múltiples operaciones asíncronas anidadas, cada una dependiente del resultado de la anterior. Esto crea un patrón de código que se desplaza horizontalmente, formando una estructura similar a una pirámide:
getUser(userId, (error, user) => {
if (error) {
console.error("Error obteniendo usuario:", error);
return;
}
getPermissions(user.id, (error, permissions) => {
if (error) {
console.error("Error obteniendo permisos:", error);
return;
}
getContent(permissions, (error, content) => {
if (error) {
console.error("Error obteniendo contenido:", error);
return;
}
processContent(content, (error, result) => {
if (error) {
console.error("Error procesando contenido:", error);
return;
}
console.log("Resultado final:", result);
});
});
});
});
Este código presenta varios problemas evidentes:
- Legibilidad reducida: La indentación excesiva dificulta seguir el flujo lógico
- Manejo repetitivo de errores: Cada nivel requiere su propio bloque de manejo de errores
- Dificultad de mantenimiento: Añadir o modificar pasos en la secuencia es propenso a errores
- Complejidad para depurar: Rastrear errores a través de múltiples niveles de anidación es complicado
Estrategias para mejorar la legibilidad
Afortunadamente, existen varias técnicas efectivas para mitigar el callback hell, incluso antes de adoptar Promises o async/await:
1. Nombrar las funciones callback
En lugar de usar funciones anónimas, podemos definir funciones con nombre:
function getUserCallback(error, user) {
if (error) {
console.error("Error obteniendo usuario:", error);
return;
}
getPermissions(user.id, getPermissionsCallback);
}
function getPermissionsCallback(error, permissions) {
if (error) {
console.error("Error obteniendo permisos:", error);
return;
}
getContent(permissions, getContentCallback);
}
function getContentCallback(error, content) {
if (error) {
console.error("Error obteniendo contenido:", error);
return;
}
processContent(content, processContentCallback);
}
function processContentCallback(error, result) {
if (error) {
console.error("Error procesando contenido:", error);
return;
}
console.log("Resultado final:", result);
}
// Iniciar la secuencia
getUser(userId, getUserCallback);
Esta técnica mejora la legibilidad al eliminar la anidación y facilita la depuración al proporcionar nombres de función en la pila de llamadas.
2. Modularización en funciones pequeñas
Podemos dividir el flujo en funciones independientes que encapsulen cada paso:
function getUserData(userId, callback) {
getUser(userId, (error, user) => {
if (error) {
callback(error);
return;
}
callback(null, user);
});
}
function getUserPermissions(user, callback) {
getPermissions(user.id, (error, permissions) => {
if (error) {
callback(error);
return;
}
callback(null, permissions);
});
}
function getContentData(permissions, callback) {
getContent(permissions, callback);
}
function processContentData(content, callback) {
processContent(content, callback);
}
// Uso secuencial más limpio
getUserData(userId, (error, user) => {
if (error) return handleError(error);
getUserPermissions(user, (error, permissions) => {
if (error) return handleError(error);
getContentData(permissions, (error, content) => {
if (error) return handleError(error);
processContentData(content, (error, result) => {
if (error) return handleError(error);
console.log("Resultado final:", result);
});
});
});
});
function handleError(error) {
console.error("Error en el proceso:", error);
}
Esta aproximación mejora la organización del código y facilita la reutilización de componentes.
3. Uso de bibliotecas de control de flujo
Antes de que Promises se volvieran estándar, bibliotecas como async.js proporcionaban utilidades para gestionar flujos asíncronos:
const async = require('async');
async.waterfall([
function(callback) {
getUser(userId, callback);
},
function(user, callback) {
getPermissions(user.id, callback);
},
function(permissions, callback) {
getContent(permissions, callback);
},
function(content, callback) {
processContent(content, callback);
}
], function(error, result) {
if (error) {
console.error("Error en el proceso:", error);
return;
}
console.log("Resultado final:", result);
});
Esta técnica elimina la anidación y proporciona un manejo de errores centralizado.
4. Patrón de paso de continuación (continuation-passing)
Este patrón consiste en pasar la lógica de continuación como un callback:
function fetchUserData(userId, continuation) {
getUser(userId, (error, user) => {
if (error) {
console.error("Error obteniendo usuario:", error);
return;
}
continuation(user);
});
}
// Uso
fetchUserData(userId, (user) => {
getPermissions(user.id, (error, permissions) => {
if (error) {
console.error("Error obteniendo permisos:", error);
return;
}
// Continuar con el flujo...
});
});
Este enfoque separa la lógica de error de la lógica principal, aunque no elimina completamente la anidación.
5. Evitar anidación excesiva con returns tempranos
Una técnica simple pero efectiva es usar returns tempranos para reducir la indentación:
getUser(userId, (error, user) => {
if (error) {
console.error("Error obteniendo usuario:", error);
return;
}
// En lugar de anidar, continuamos en el mismo nivel
getUserPosts(user.id, handleUserPosts);
});
function handleUserPosts(error, posts) {
if (error) {
console.error("Error obteniendo posts:", error);
return;
}
// Procesamiento adicional
console.log(`Encontrados ${posts.length} posts`);
}
Esta técnica mejora la legibilidad al evitar niveles adicionales de indentación.
Patrones avanzados para gestionar callbacks
Patrón de eventos para operaciones asíncronas
El patrón de eventos puede ser una alternativa a los callbacks anidados:
const EventEmitter = require('events');
const userProcessor = new EventEmitter();
// Configurar manejadores de eventos
userProcessor.on('got-user', (user) => {
console.log("Usuario obtenido:", user.name);
getPermissions(user.id, (error, permissions) => {
if (error) {
userProcessor.emit('error', error);
return;
}
userProcessor.emit('got-permissions', permissions);
});
});
userProcessor.on('got-permissions', (permissions) => {
console.log("Permisos obtenidos");
// Continuar el flujo...
});
userProcessor.on('error', (error) => {
console.error("Error en el proceso:", error);
});
// Iniciar el proceso
getUser(userId, (error, user) => {
if (error) {
userProcessor.emit('error', error);
return;
}
userProcessor.emit('got-user', user);
});
Este patrón desacopla las operaciones y permite manejar flujos más complejos, aunque introduce su propia complejidad.
Implementación de máquinas de estado
Para flujos muy complejos, una máquina de estado puede ser apropiada:
const stateMachine = {
state: 'init',
data: {},
// Transiciones
init() {
this.state = 'fetching-user';
getUser(userId, this.handleUser.bind(this));
},
handleUser(error, user) {
if (error) {
this.state = 'error';
this.error = error;
this.logError();
return;
}
this.data.user = user;
this.state = 'fetching-permissions';
getPermissions(user.id, this.handlePermissions.bind(this));
},
handlePermissions(error, permissions) {
if (error) {
this.state = 'error';
this.error = error;
this.logError();
return;
}
this.data.permissions = permissions;
this.state = 'complete';
this.processResult();
},
logError() {
console.error(`Error en estado ${this.state}:`, this.error);
},
processResult() {
console.log("Proceso completado con datos:", this.data);
}
};
// Iniciar la máquina
stateMachine.init();
Este enfoque organiza el código según estados del proceso, facilitando el seguimiento del flujo lógico.
Limitaciones adicionales de los callbacks
Además del callback hell, los callbacks presentan otras limitaciones importantes:
- Dificultad para manejar operaciones paralelas: Coordinar múltiples operaciones asíncronas simultáneas requiere código adicional
- Problemas con el manejo de excepciones: Las excepciones lanzadas dentro de callbacks asíncronos no pueden capturarse con try/catch convencional
- Dificultad para implementar patrones de control de flujo: Operaciones como retry, timeout o race son complejas de implementar
- Inversión de control: Al usar callbacks, cedemos el control de la ejecución a la función que recibe nuestro callback
// Problema con excepciones en callbacks
try {
setTimeout(() => {
throw new Error("Este error no será capturado");
}, 100);
} catch (error) {
// Este bloque nunca se ejecutará
console.error("Error capturado:", error);
}
Transición hacia soluciones modernas
Aunque las estrategias mencionadas mejoran el trabajo con callbacks, las soluciones modernas como Promises y async/await ofrecen ventajas significativas:
// Versión con Promises
getUserAsync(userId)
.then(user => getPermissionsAsync(user.id))
.then(permissions => getContentAsync(permissions))
.then(content => processContentAsync(content))
.then(result => {
console.log("Resultado final:", result);
})
.catch(error => {
console.error("Error en el proceso:", error);
});
// Versión con async/await
async function processUserData(userId) {
try {
const user = await getUserAsync(userId);
const permissions = await getPermissionsAsync(user.id);
const content = await getContentAsync(permissions);
const result = await processContentAsync(content);
console.log("Resultado final:", result);
} catch (error) {
console.error("Error en el proceso:", error);
}
}
Estas aproximaciones resuelven fundamentalmente muchos de los problemas inherentes a los callbacks, proporcionando código más legible, mejor manejo de errores y mayor facilidad para implementar patrones de control de flujo complejos.
A pesar de sus limitaciones, entender los callbacks y sus problemas es esencial para apreciar completamente las ventajas de las abstracciones modernas y para trabajar efectivamente con código legacy o APIs basadas en callbacks que aún son comunes en el ecosistema de JavaScript.
Otros ejercicios de programación de JavaScript
Evalúa tus conocimientos de esta lección Callbacks con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Clases y objetos
Uso de operadores
Uso de operadores
Estructuras de control
Proyecto Manipulación DOM
Excepciones
Transformación con map()
Arrays y Métodos
Reto Métodos de Strings
Transformación con map()
Funciones flecha
Async / Await
Selección de elementos DOM
API Fetch
Encapsulación
Mapas con Map
Creación y uso de variables
Polimorfismo
Reto Funciones flecha
Tipos de datos
Reto Operadores avanzados
Promises
Reto Estructuras de control
Estructuras de control
Pruebas unitarias
Inmutabilidad y programación funcional pura
Funciones flecha
Polimorfismo
Reto Polimorfismo
Array
Transformación con map()
Reto Variables
Gestor de tareas con JavaScript
Proyecto Modificación de elementos DOM
Manipulación DOM
Funciones
Conjuntos con Set
Reto Prototipos y cadena de prototipos
Reto Encapsulación
Funciones flecha
Async / Await
Reto Excepciones
Reto Filtrado con filter() y find()
Creación y uso de variables
Excepciones
Promises
Funciones cierre (closure)
Reto Herencia
Herencia
Proyecto Eventos del DOM
Herencia
Selección de elementos DOM
Modificación de elementos DOM
Reto Clases y objetos
Filtrado con filter() y find()
Funciones cierre (closure)
Reto Destructuring de objetos y arrays
Callbacks
Funciones
Mapas con Map
Reducción con reduce()
Callbacks
Manipulación DOM
Introducción al DOM
Reto Funciones
Reto Funciones cierre (closure)
Promises
Reto Reducción con reduce()
Async / Await
Reto Estructuras de control
Eventos del DOM
Introducción a JavaScript
Async / Await
Promises
Selección de elementos DOM
Filtrado con filter() y find()
Callbacks
Creación de clases y objetos Restaurante
Reducción con reduce()
Filtrado con filter() y find()
Reducción con reduce()
Conjuntos con Set
Herencia de clases
Eventos del DOM
Clases y objetos
Modificación de elementos DOM
Mapas con Map
Proyecto carrito compra agoodshop
Introducción a JavaScript
Reto Mapas con Map
Funciones
Proyecto administrador de contactos
Reto Expresiones regulares
Tipos de datos
Clases y objetos
Array
Conjuntos con Set
Array
Encapsulación
Todas las lecciones de JavaScript
Accede a todas las lecciones de JavaScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Javascript
Introducción Y Entorno
Tipos De Datos
Sintaxis
Variables
Sintaxis
Operadores
Sintaxis
Estructuras De Control
Sintaxis
Funciones
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Métodos De Strings
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Operadores Avanzados
Sintaxis
Funciones
Sintaxis
Expresiones Regulares
Sintaxis
Estructuras De Control
Sintaxis
Arrays Y Métodos
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Mapas Con Map
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Funciones Flecha
Programación Funcional
Filtrado Con Filter() Y Find()
Programación Funcional
Transformación Con Map()
Programación Funcional
Reducción Con Reduce()
Programación Funcional
Funciones Flecha
Programación Funcional
Transformación Con Map()
Programación Funcional
Inmutabilidad Y Programación Funcional Pura
Programación Funcional
Clases Y Objetos
Programación Orientada A Objetos
Excepciones
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
This Y Contexto
Programación Orientada A Objetos
Patrón De Módulos Y Namespace
Programación Orientada A Objetos
Prototipos Y Cadena De Prototipos
Programación Orientada A Objetos
Destructuring De Objetos Y Arrays
Programación Orientada A Objetos
Manipulación Dom
Dom
Selección De Elementos Dom
Dom
Modificación De Elementos Dom
Dom
Eventos Del Dom
Dom
Localstorage Y Sessionstorage
Dom
Bom (Browser Object Model)
Dom
Callbacks
Programación Asíncrona
Promises
Programación Asíncrona
Async / Await
Programación Asíncrona
Promises
Programación Asíncrona
Api Fetch
Programación Asíncrona
Async / Await
Programación Asíncrona
Naturaleza De Js Y Event Loop
Programación Asíncrona
Callbacks
Programación Asíncrona
Websockets
Programación Asíncrona
Módulos En Es6
Construcción
Configuración De Bundlers Como Vite
Construcción
Eslint Y Calidad De Código
Construcción
Npm Y Dependencias
Construcción
Introducción A Pruebas En Js
Testing
Pruebas Unitarias
Testing
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender qué son y cómo funcionan las funciones de orden superior en JavaScript.
- Aplicar funciones de orden superior para mejorar patrones asíncronos.
- Implementar funciones que devuelvan otras funciones y funciones como valores.
- Manejar asincronía con callbacks usando funciones de orden superior.
- Mejorar la legibilidad y organización del código con funciones de orden superior.
- Implementar patrones de programación funcional aplicados a la asincronía.