JavaScript
Tutorial JavaScript: Excepciones
JavaScript excepciones: manejo y prevención. Domina el manejo de excepciones en JavaScript con técnicas y ejemplos prácticos.
Aprende JavaScript y certifícateFundamentos del manejo de excepciones: Captura y lanzamiento de errores en JavaScript
El manejo de excepciones es una técnica fundamental en la programación que permite controlar situaciones inesperadas o erróneas durante la ejecución de nuestro código. En JavaScript, este mecanismo nos ayuda a identificar, capturar y responder a errores de forma estructurada, evitando que nuestra aplicación se detenga abruptamente.
Errores en JavaScript
JavaScript proporciona un sistema de errores basado en objetos que heredan de la clase Error
. Cuando ocurre un problema durante la ejecución, el intérprete genera (o "lanza") un objeto de error que contiene información sobre lo sucedido.
Los tipos de errores nativos más comunes son:
Error
: El tipo base para todos los erroresSyntaxError
: Errores de sintaxis en el códigoReferenceError
: Referencias a variables o funciones inexistentesTypeError
: Operaciones sobre tipos de datos incorrectosRangeError
: Valores fuera del rango permitido
Cada objeto de error contiene propiedades útiles:
try {
nonExistentFunction();
} catch (error) {
console.log(error.name); // "ReferenceError"
console.log(error.message); // "nonExistentFunction is not defined"
console.log(error.stack); // Traza de la pila de llamadas
}
Estructura try-catch-finally
El bloque try-catch-finally
es la estructura básica para manejar excepciones en JavaScript:
try {
// Código que podría generar un error
} catch (error) {
// Código que se ejecuta si ocurre un error
} finally {
// Código que se ejecuta siempre, haya error o no
}
Cada parte cumple una función específica:
- El bloque
try
contiene el código que queremos "proteger" y que podría generar errores. - El bloque
catch
se ejecuta solo si ocurre un error en el bloquetry
. - El bloque
finally
(opcional) se ejecuta siempre, independientemente de si hubo un error o no.
Un ejemplo práctico:
function divideNumbers(a, b) {
try {
if (b === 0) {
throw new Error("Cannot divide by zero");
}
const result = a / b;
return result;
} catch (error) {
console.error(`Error occurred: ${error.message}`);
return null;
} finally {
console.log("Division operation attempted");
}
}
console.log(divideNumbers(10, 2)); // 5
console.log(divideNumbers(10, 0)); // null (después de mostrar el error)
Lanzamiento de errores con throw
La palabra clave throw
permite generar errores manualmente cuando detectamos condiciones inválidas en nuestro código:
function validateAge(age) {
if (typeof age !== 'number') {
throw new TypeError("Age must be a number");
}
if (age < 0 || age > 120) {
throw new RangeError("Age must be between 0 and 120");
}
return true;
}
try {
validateAge("twenty"); // Lanzará TypeError
} catch (error) {
console.error(error.name + ": " + error.message);
}
Podemos lanzar cualquier tipo de error nativo o crear nuestros propios tipos personalizados:
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
function processUserData(user) {
if (!user.name) {
throw new ValidationError("User name is required");
}
// Continuar procesando...
}
Captura selectiva de errores
Podemos discriminar entre diferentes tipos de errores para manejarlos de forma específica:
try {
// Código que podría generar diferentes tipos de errores
const data = JSON.parse(userInput);
processData(data);
} catch (error) {
if (error instanceof SyntaxError) {
console.error("Invalid JSON format");
} else if (error instanceof ReferenceError) {
console.error("Missing reference in the data");
} else {
console.error("An unexpected error occurred:", error);
}
}
Propagación de errores
A veces es mejor propagar un error hacia arriba en la pila de llamadas para que sea manejado por un nivel superior:
function validateData(data) {
if (!data.id) {
throw new Error("Missing ID field");
}
return true;
}
function processUserRecord(record) {
try {
validateData(record);
// Continuar procesando...
} catch (error) {
// Añadir contexto al error y propagarlo
throw new Error(`Error processing user record: ${error.message}`);
}
}
try {
processUserRecord({name: "John"});
} catch (error) {
console.error("Application error:", error.message);
// Mostrar mensaje amigable al usuario
}
Errores en funciones anidadas
Los errores se propagan automáticamente hacia arriba a través de las llamadas a funciones hasta encontrar un bloque catch
:
function innerFunction() {
throw new Error("Inner error");
}
function middleFunction() {
innerFunction(); // El error se propaga hacia arriba
}
function outerFunction() {
try {
middleFunction();
} catch (error) {
console.error("Caught in outer function:", error.message);
}
}
outerFunction(); // "Caught in outer function: Inner error"
Buenas prácticas básicas
- Sé específico: Captura solo los errores que puedes manejar adecuadamente.
- Proporciona mensajes claros: Los mensajes de error deben ser descriptivos y útiles.
- No abuses de try-catch: Úsalo para condiciones excepcionales, no para el flujo normal del programa.
- Considera el rendimiento: Los bloques try-catch tienen un pequeño impacto en el rendimiento.
// Enfoque recomendado
function getUserData(userId) {
if (!userId) {
throw new Error("User ID is required");
}
try {
return fetchUserFromDatabase(userId);
} catch (error) {
console.error(`Failed to fetch user ${userId}:`, error.message);
throw new Error(`Could not retrieve user data: ${error.message}`);
}
}
El manejo adecuado de excepciones mejora la robustez de nuestras aplicaciones y proporciona una mejor experiencia tanto para los desarrolladores como para los usuarios finales, permitiéndonos anticipar y responder a situaciones problemáticas de manera controlada.
Diseño de estrategias robustas para el control de errores: Patrones y mejores prácticas
El manejo de excepciones va más allá de simplemente usar bloques try-catch
. Un enfoque estratégico al control de errores puede mejorar significativamente la robustez, mantenibilidad y experiencia de usuario de nuestras aplicaciones JavaScript. Vamos a explorar patrones y prácticas que nos ayudarán a diseñar sistemas más resilientes.
Jerarquía de errores personalizados
Crear una jerarquía de errores bien estructurada permite categorizar problemas y facilitar su manejo específico:
// Error base para toda la aplicación
class AppError extends Error {
constructor(message, statusCode = 500) {
super(message);
this.name = this.constructor.name;
this.statusCode = statusCode;
Error.captureStackTrace(this, this.constructor);
}
}
// Errores específicos por dominio
class ValidationError extends AppError {
constructor(message) {
super(message, 400);
this.validationErrors = [];
}
addValidationError(field, message) {
this.validationErrors.push({ field, message });
return this;
}
}
class AuthorizationError extends AppError {
constructor(message) {
super(message, 403);
}
}
Esta estructura permite un manejo contextual de errores:
function processUserInput(data) {
try {
if (!data.username) {
const error = new ValidationError("Invalid user data")
.addValidationError("username", "Username is required");
throw error;
}
// Más validaciones...
} catch (error) {
if (error instanceof ValidationError) {
// Mostrar errores de validación en la interfaz
displayValidationErrors(error.validationErrors);
} else {
// Manejar otros tipos de errores
logErrorAndNotify(error);
}
}
}
Patrón de fábrica de errores
El patrón de fábrica centraliza la creación de errores, garantizando consistencia en toda la aplicación:
// Fábrica de errores
const ErrorFactory = {
createNotFoundError(resource, id) {
const error = new AppError(`${resource} with id ${id} not found`, 404);
error.resource = resource;
error.resourceId = id;
return error;
},
createValidationError(fieldErrors) {
const error = new ValidationError("Validation failed");
fieldErrors.forEach(({ field, message }) => {
error.addValidationError(field, message);
});
return error;
},
createNetworkError(endpoint, originalError) {
const error = new AppError(`Failed to connect to ${endpoint}`, 503);
error.originalError = originalError;
return error;
}
};
// Uso
function fetchUser(userId) {
if (!userExists(userId)) {
throw ErrorFactory.createNotFoundError("User", userId);
}
// Continuar con la lógica...
}
Patrón de envoltura de errores
La envoltura de errores preserva el contexto original mientras añade información valiosa en cada nivel:
function processPayment(paymentData) {
try {
validatePaymentData(paymentData);
chargeCustomer(paymentData);
sendReceipt(paymentData);
} catch (error) {
// Envolver el error con contexto adicional
const wrappedError = new AppError(
`Payment processing failed: ${error.message}`,
error.statusCode || 500
);
// Preservar el error original y añadir contexto
wrappedError.originalError = error;
wrappedError.paymentReference = paymentData.reference;
throw wrappedError;
}
}
Centralización del manejo de errores
Un manejador centralizado proporciona consistencia y evita la duplicación de código:
// Manejador central de errores
const ErrorHandler = {
handle(error, context = {}) {
// Registrar el error
this.logError(error, context);
// Determinar la respuesta apropiada
if (error instanceof ValidationError) {
return this.handleValidationError(error);
} else if (error instanceof AuthorizationError) {
return this.handleAuthError(error);
} else {
return this.handleGenericError(error);
}
},
logError(error, context) {
console.error({
message: error.message,
name: error.name,
stack: error.stack,
context,
timestamp: new Date().toISOString()
});
},
handleValidationError(error) {
return {
success: false,
status: error.statusCode,
errors: error.validationErrors,
message: "Validation failed"
};
},
// Otros manejadores específicos...
handleGenericError(error) {
// Ocultar detalles técnicos en producción
const isProduction = process.env.NODE_ENV === 'production';
return {
success: false,
status: error.statusCode || 500,
message: isProduction ? "An unexpected error occurred" : error.message
};
}
};
// Uso en una API
app.post('/api/users', (req, res) => {
try {
const user = createUser(req.body);
res.json({ success: true, user });
} catch (error) {
const response = ErrorHandler.handle(error, {
endpoint: '/api/users',
method: 'POST'
});
res.status(response.status).json(response);
}
});
Recuperación elegante
La recuperación elegante permite que el sistema continúe funcionando incluso cuando ocurren errores:
function loadUserPreferences(userId) {
try {
return fetchUserPreferences(userId);
} catch (error) {
// Registrar el error
console.warn(`Failed to load preferences for user ${userId}:`, error);
// Proporcionar valores predeterminados como fallback
return getDefaultPreferences();
}
}
function getDefaultPreferences() {
return {
theme: 'light',
notifications: true,
language: 'en'
};
}
Validación preventiva
La validación temprana puede evitar errores antes de que ocurran:
function transferFunds(fromAccount, toAccount, amount) {
// Validación preventiva
if (typeof amount !== 'number' || amount <= 0) {
throw new ValidationError("Amount must be a positive number");
}
if (!fromAccount || !toAccount) {
throw new ValidationError("Both accounts are required");
}
// Verificar fondos suficientes antes de intentar la transferencia
if (fromAccount.balance < amount) {
throw new AppError("Insufficient funds", 400);
}
// Proceder con la transferencia...
}
Monitoreo y análisis de errores
Implementar un sistema de monitoreo de errores permite identificar patrones y problemas recurrentes:
class ErrorMonitor {
constructor() {
this.errorCounts = new Map();
this.errorSamples = new Map();
}
trackError(error) {
const errorType = error.name;
// Incrementar contador
const currentCount = this.errorCounts.get(errorType) || 0;
this.errorCounts.set(errorType, currentCount + 1);
// Guardar muestra del error
if (!this.errorSamples.has(errorType)) {
this.errorSamples.set(errorType, {
message: error.message,
stack: error.stack,
firstSeen: new Date(),
lastSeen: new Date()
});
} else {
const sample = this.errorSamples.get(errorType);
sample.lastSeen = new Date();
sample.occurrences = (sample.occurrences || 1) + 1;
}
// Alertar si un error ocurre con frecuencia
if (currentCount + 1 >= 10) {
this.triggerAlert(errorType);
}
}
getErrorReport() {
return {
summary: Object.fromEntries(this.errorCounts),
samples: Object.fromEntries(this.errorSamples)
};
}
triggerAlert(errorType) {
console.error(`ALERT: High frequency of ${errorType} errors detected!`);
// Enviar notificación al equipo de desarrollo
}
}
// Uso global
const monitor = new ErrorMonitor();
// Integración con el manejador de errores
const originalHandleMethod = ErrorHandler.handle;
ErrorHandler.handle = function(error, context) {
monitor.trackError(error);
return originalHandleMethod.call(this, error, context);
};
Estrategias de reintentos
Para operaciones que pueden fallar temporalmente, como peticiones de red, una estrategia de reintentos puede aumentar la resiliencia:
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fetch(url, options);
} catch (error) {
lastError = error;
// Solo reintentar en errores de red, no en errores de servidor
if (!isNetworkError(error)) {
throw error;
}
console.warn(`Attempt ${attempt} failed, retrying...`, error.message);
// Esperar con backoff exponencial antes de reintentar
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
// Si llegamos aquí, todos los intentos fallaron
throw new AppError(`Failed after ${maxRetries} attempts: ${lastError.message}`, 503);
}
function isNetworkError(error) {
return error.message.includes('network') ||
error.message.includes('connection') ||
error.message.includes('timeout');
}
Contratos y precondiciones
Establecer contratos claros mediante precondiciones ayuda a detectar errores temprano:
function calculateDiscount(product, user) {
// Precondiciones
assert(product, "Product is required");
assert(user, "User is required");
assert(typeof product.price === 'number', "Product price must be a number");
// Lógica de negocio
let discount = 0;
if (user.isPremium) {
discount = product.price * 0.1;
}
if (product.isOnSale) {
discount += product.price * 0.05;
}
// Postcondición
assert(discount >= 0, "Discount cannot be negative");
return discount;
}
function assert(condition, message) {
if (!condition) {
throw new Error(`Assertion failed: ${message}`);
}
}
Estas estrategias y patrones, aplicados de manera consistente, crean un sistema de manejo de errores que no solo responde a problemas, sino que los anticipa y minimiza su impacto, resultando en aplicaciones más robustas y una mejor experiencia para los usuarios.
Manejo de excepciones en contextos asíncronos: Promesas, async/await y entornos distribuidos
El manejo de errores en código asíncrono presenta desafíos únicos que van más allá de los bloques try-catch tradicionales. En JavaScript moderno, donde las operaciones asíncronas son fundamentales, necesitamos estrategias específicas para capturar y gestionar excepciones en promesas, funciones async/await y entornos distribuidos.
Errores en promesas
Las promesas en JavaScript tienen su propio mecanismo para manejar errores a través del método .catch()
:
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return response.json();
})
.then(data => console.log('Data received:', data))
.catch(error => {
console.error('Fetch operation failed:', error.message);
});
Un aspecto crucial de las promesas es que los errores se propagan automáticamente a través de la cadena de .then()
hasta encontrar un .catch()
:
fetchUserData(userId)
.then(user => processUser(user)) // Si fetchUserData falla, este paso se omite
.then(result => saveToDatabase(result)) // Este también se omite
.catch(error => {
// Captura errores de cualquier paso anterior
console.error('Operation failed:', error);
});
Promesas rechazadas no capturadas
Uno de los problemas más comunes en aplicaciones JavaScript es no capturar rechazos de promesas, lo que puede causar fugas de memoria y comportamientos inesperados. Podemos detectar estos casos con:
window.addEventListener('unhandledrejection', event => {
console.error('Unhandled promise rejection:', event.reason);
// Registrar el error o notificar al usuario
event.preventDefault(); // Evita que el error aparezca en la consola
});
En Node.js:
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise);
console.error('Reason:', reason);
// Posiblemente: process.exit(1);
});
Manejo de errores con async/await
La sintaxis async/await simplifica el manejo de errores asíncronos permitiendo usar bloques try-catch tradicionales:
async function getUserData(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const userData = await response.json();
return userData;
} catch (error) {
console.error(`Failed to fetch user ${userId}:`, error);
throw new Error(`Could not retrieve user data: ${error.message}`);
}
}
Sin embargo, es importante recordar que una función async siempre devuelve una promesa, por lo que los errores deben manejarse adecuadamente cuando se llama a estas funciones:
// Opción 1: Usando .catch()
getUserData(123)
.then(user => displayUserProfile(user))
.catch(error => showErrorMessage(error.message));
// Opción 2: Usando async/await con try-catch
async function displayUser(userId) {
try {
const user = await getUserData(userId);
displayUserProfile(user);
} catch (error) {
showErrorMessage(error.message);
}
}
Patrones para operaciones asíncronas paralelas
Cuando ejecutamos múltiples operaciones asíncronas en paralelo, tenemos diferentes opciones para manejar errores:
- Promise.all(): Falla rápido si cualquier promesa es rechazada
async function loadDashboardData(userId) {
try {
const [profile, posts, notifications] = await Promise.all([
fetchUserProfile(userId),
fetchUserPosts(userId),
fetchNotifications(userId)
]);
return { profile, posts, notifications };
} catch (error) {
// Si cualquier operación falla, entramos aquí
console.error('Dashboard data loading failed:', error);
throw error;
}
}
- Promise.allSettled(): Espera a que todas las promesas se completen, independientemente del resultado
async function loadDashboardData(userId) {
const results = await Promise.allSettled([
fetchUserProfile(userId),
fetchUserPosts(userId),
fetchNotifications(userId)
]);
// Procesar resultados individualmente
const dashboard = {};
if (results[0].status === 'fulfilled') {
dashboard.profile = results[0].value;
} else {
console.error('Profile loading failed:', results[0].reason);
dashboard.profile = getDefaultProfile();
}
// Procesar el resto de resultados...
return dashboard;
}
Timeouts en operaciones asíncronas
Para evitar que las operaciones asíncronas se bloqueen indefinidamente, podemos implementar timeouts:
function fetchWithTimeout(url, options = {}, timeout = 5000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Request timeout')), timeout)
)
]);
}
// Uso
async function getApiData() {
try {
const response = await fetchWithTimeout('https://api.example.com/data', {}, 3000);
return response.json();
} catch (error) {
if (error.message === 'Request timeout') {
// Manejar específicamente el timeout
console.error('The request took too long to complete');
} else {
// Manejar otros errores
console.error('API request failed:', error);
}
return null;
}
}
Manejo de errores en operaciones de red
Las aplicaciones modernas a menudo dependen de servicios externos, lo que introduce puntos de fallo adicionales. Una estrategia robusta incluye:
async function fetchWithErrorHandling(url) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const response = await fetch(url, {
signal: controller.signal,
headers: { 'Content-Type': 'application/json' }
});
clearTimeout(timeoutId);
if (!response.ok) {
// Manejar errores HTTP
if (response.status === 404) {
throw new NotFoundError(`Resource not found: ${url}`);
} else if (response.status === 401 || response.status === 403) {
throw new AuthError('Authentication required');
} else {
throw new ApiError(`Server responded with ${response.status}`);
}
}
return await response.json();
} catch (error) {
// Categorizar errores de red
if (error.name === 'AbortError') {
throw new TimeoutError('Request timed out');
} else if (error instanceof TypeError && error.message.includes('network')) {
throw new NetworkError('Network connection failed');
}
// Propagar errores ya categorizados
throw error;
}
}
Manejo de errores en eventos asíncronos
Para APIs basadas en eventos como WebSockets, necesitamos un enfoque diferente:
function setupWebSocketWithErrorHandling(url) {
const socket = new WebSocket(url);
// Manejar errores de conexión
socket.addEventListener('error', event => {
console.error('WebSocket error:', event);
notifyUser('Connection error occurred');
});
// Manejar desconexiones
socket.addEventListener('close', event => {
if (!event.wasClean) {
console.warn(`Connection closed abnormally, code: ${event.code}`);
// Implementar reconexión con backoff exponencial
reconnectWithBackoff(url);
}
});
return socket;
}
// Implementación de reconexión con backoff exponencial
let reconnectAttempt = 0;
function reconnectWithBackoff(url) {
const maxReconnectAttempts = 5;
if (reconnectAttempt >= maxReconnectAttempts) {
console.error('Maximum reconnection attempts reached');
notifyUser('Unable to establish connection');
return;
}
const delay = Math.min(1000 * Math.pow(2, reconnectAttempt), 30000);
console.log(`Attempting to reconnect in ${delay}ms...`);
setTimeout(() => {
reconnectAttempt++;
setupWebSocketWithErrorHandling(url);
}, delay);
}
Manejo de errores en microfrontends y arquitecturas distribuidas
En aplicaciones distribuidas, los errores pueden ocurrir en diferentes contextos y fronteras:
// Comunicación entre microfrontends
window.addEventListener('error', event => {
// Evitar bucles infinitos verificando el origen
if (event.error && event.error.fromMicroFrontend) {
return;
}
// Notificar al sistema principal
window.parent.postMessage({
type: 'ERROR',
payload: {
message: event.error?.message || 'Unknown error',
source: 'userProfileMicrofrontend',
timestamp: Date.now(),
fromMicroFrontend: true
}
}, '*');
});
// En la aplicación principal
window.addEventListener('message', event => {
if (event.data.type === 'ERROR') {
const { source, message } = event.data.payload;
console.error(`Error in ${source}:`, message);
// Centralizar el registro de errores
errorMonitoringService.captureError({
context: 'microfrontend',
source,
message,
level: 'error'
});
}
});
Estrategias de circuit breaker para APIs externas
El patrón circuit breaker previene fallos en cascada cuando un servicio externo está experimentando problemas:
class CircuitBreaker {
constructor(request, options = {}) {
this.request = request;
this.state = 'CLOSED';
this.failureCount = 0;
this.successCount = 0;
this.lastFailureTime = null;
this.failureThreshold = options.failureThreshold || 3;
this.resetTimeout = options.resetTimeout || 30000;
this.monitorInterval = options.monitorInterval || 5000;
}
async execute(...args) {
if (this.state === 'OPEN') {
// Verificar si debemos intentar restablecer el circuito
if (Date.now() - this.lastFailureTime > this.resetTimeout) {
this.state = 'HALF_OPEN';
console.log('Circuit breaker state: HALF_OPEN');
} else {
throw new Error('Circuit is OPEN - request rejected');
}
}
try {
const result = await this.request(...args);
// En estado semi-abierto, un éxito restablece el circuito
if (this.state === 'HALF_OPEN') {
this.successCount++;
if (this.successCount >= 2) {
this.reset();
}
}
return result;
} catch (error) {
this.recordFailure(error);
throw error;
}
}
recordFailure(error) {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.state === 'CLOSED' && this.failureCount >= this.failureThreshold) {
this.state = 'OPEN';
console.warn('Circuit breaker state: OPEN');
}
console.error(`Service call failed (${this.failureCount} failures)`, error);
}
reset() {
this.state = 'CLOSED';
this.failureCount = 0;
this.successCount = 0;
console.log('Circuit breaker reset: CLOSED');
}
}
// Uso
const apiClient = new CircuitBreaker(
(endpoint) => fetch(`https://api.example.com/${endpoint}`).then(r => r.json()),
{ failureThreshold: 3, resetTimeout: 10000 }
);
async function getUserData(userId) {
try {
return await apiClient.execute(`users/${userId}`);
} catch (error) {
if (error.message.includes('Circuit is OPEN')) {
return getCachedUserData(userId);
}
throw error;
}
}
El manejo efectivo de excepciones en contextos asíncronos requiere una combinación de técnicas específicas para cada patrón de asincronía. Al implementar estas estrategias, podemos crear aplicaciones JavaScript que no solo funcionan correctamente en condiciones ideales, sino que también son resilientes frente a fallos en entornos distribuidos y redes poco confiables.
Ejercicios de esta lección Excepciones
Evalúa tus conocimientos de esta lección Excepciones con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Funciones flecha
Polimorfismo
Array
Transformación con map()
Gestor de tareas con JavaScript
Manipulación DOM
Funciones
Funciones flecha
Async / Await
Creación y uso de variables
Excepciones
Promises
Funciones cierre (closure)
Herencia
Herencia
Estructuras de control
Selección de elementos DOM
Modificación de elementos DOM
Filtrado con filter() y find()
Funciones cierre (closure)
Funciones
Mapas con Map
Reducción con reduce()
Callbacks
Manipulación DOM
Promises
Async / Await
Eventos del DOM
Async / Await
Promises
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
Introducción a JavaScript
Funciones
Tipos de datos
Clases y objetos
Array
Conjuntos con Set
Array
Encapsulación
Clases y objetos
Uso de operadores
Uso de operadores
Estructuras de control
Excepciones
Transformación con map()
Funciones flecha
Selección de elementos DOM
Encapsulación
Mapas con Map
Creación y uso de variables
Polimorfismo
Tipos de datos
Estructuras de control
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
Arrays Y Métodos
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Mapas Con Map
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
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
Manipulación Dom
Dom
Selección De Elementos Dom
Dom
Modificación De Elementos Dom
Dom
Eventos Del Dom
Dom
Callbacks
Programación Asíncrona
Promises
Programación Asíncrona
Async / Await
Programación Asíncrona
Certificados de superación de JavaScript
Supera todos los ejercicios de programación del curso de JavaScript y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender qué son las excepciones y por qué son importantes en JavaScript.
- Conocer la estructura
try-catch-finally
y cómo se utiliza para manejar excepciones. - Entender la función de cada bloque (
try
,catch
,finally
) en el manejo de excepciones. - Aprender a lanzar y capturar excepciones usando la palabra clave
throw
. - Saber cómo utilizar múltiples bloques
catch
para manejar diferentes tipos de excepciones. - Comprender la utilidad del bloque
finally
para ejecutar código que debe ejecutarse siempre, independientemente de si ocurrió una excepción o no. - Aprender a personalizar los mensajes de error en las excepciones para brindar información más específica.
- Entender cómo el manejo adecuado de excepciones mejora la robustez y la legibilidad del código.