Command Palette

Search for a command to run...

Error Boundaries: Patrones de Manejo de Errores en JavaScript

Aprende el concepto de error boundaries para manejar errores en diferentes niveles de tu aplicación con patrones prácticos en JavaScript vanilla.

Lectura: 10 min
Nivel: Intermedio

TL;DR - Resumen rápido

  • Los error boundaries son patrones para capturar errores en niveles específicos de la aplicación
  • Implementa boundaries usando try/catch estratégicamente en diferentes capas
  • Los boundaries previenen que un error local afecte todo el sistema
  • Usa boundaries a nivel de función, módulo y aplicación para máxima resiliencia
  • Los patrones de fallback UI y reintentos mejoran la experiencia del usuario

Introducción

En aplicaciones modernas, los errores pueden ocurrir en cualquier parte del código y, si no se manejan adecuadamente, pueden hacer que toda la aplicación colapse. Los error boundaries son un patrón de diseño que permite capturar errores en niveles específicos de la aplicación, evitando que un error local afecte a todo el sistema.

Aunque el término "Error Boundaries" se popularizó con React, el concepto es aplicable a cualquier arquitectura de JavaScript. La idea fundamental es encapsular partes de tu aplicación en "fronteras" que capturan errores y proporcionan una recuperación controlada, mostrando una UI de fallback o registrando el error sin interrumpir la experiencia del usuario. Los error boundaries funcionan como escudos que protegen partes de tu aplicación. Si un error ocurre dentro de un boundary, el boundary captura el error y evita que se propague a niveles superiores, manteniendo el resto de la aplicación funcional.

¿Qué son los Error Boundaries?

Los error boundaries son patrones arquitectónicos que delimitan áreas de tu aplicación donde los errores se capturan y manejan localmente. En lugar de dejar que un error se propague hasta el nivel más alto de la aplicación (donde podría causar un colapso completo), los boundaries interceptan el error en un nivel específico y toman medidas correctivas.

Este patrón es especialmente útil en aplicaciones modulares donde diferentes componentes o módulos pueden fallar independientemente. Con boundaries, puedes asegurar que un error en un módulo no afecte a otros módulos que funcionan correctamente, mejorando la resiliencia general de la aplicación.

Concepto General en JavaScript

En JavaScript vanilla, el concepto de error boundaries se implementa mediante el uso estratégico de bloques try/catch en diferentes niveles de tu aplicación. Cada boundary representa una capa de protección donde los errores se capturan y manejan antes de que puedan propagarse.

concepto-boundary.js
Loading code...

Este ejemplo muestra el concepto básico de un error boundary en JavaScript. El módulo A tiene su propio boundary que captura errores internos sin afectar al módulo B. Si el módulo A falla, el boundary captura el error y puede mostrar un mensaje de error o intentar recuperar, mientras que el módulo B continúa funcionando normalmente.

  • <strong>Boundary de Módulo</strong>: Captura errores en un módulo específico
  • <strong>Boundary de Función</strong>: Protege funciones individuales
  • <strong>Boundary Global</strong>: Captura errores que no fueron manejados en niveles inferiores
  • <strong>Boundary de UI</strong>: Muestra una interfaz de fallback cuando falla un componente

Implementación en JavaScript Vanilla

Para implementar error boundaries en JavaScript vanilla, necesitas identificar los puntos críticos de tu aplicación donde los errores deben capturarse. Estos puntos suelen ser: entrada de usuario, llamadas a APIs, procesamiento de datos y renderizado de UI.

Boundary a Nivel de Función

El nivel más básico de error boundary es a nivel de función. Aquí envuelves funciones específicas en bloques try/catch para capturar errores que puedan ocurrir durante su ejecución.

boundary-funciones.js
Loading code...

Este ejemplo muestra cómo crear un boundary a nivel de función usando un wrapper. La función withErrorBoundary envuelve cualquier función y captura errores, proporcionando un valor por defecto o manejando el error de forma controlada. Esto es especialmente útil para funciones que procesan datos de usuario o realizan operaciones críticas. Crear un wrapper reutilizable como withErrorBoundary te permite aplicar el patrón de boundary a múltiples funciones sin duplicar código, personalizándolo para diferentes casos de uso como logging, retries o valores por defecto.

Boundary a Nivel de Módulo

Los boundaries a nivel de módulo protegen secciones completas de tu aplicación. Cada módulo puede tener su propio boundary que captura errores internos y evita que afecten a otros módulos.

boundary-modulos.js
Loading code...

Este ejemplo muestra cómo implementar boundaries a nivel de módulo. Cada módulo tiene su propio boundary que captura errores internos. El módulo de autenticación puede fallar sin afectar al módulo de dashboard, y viceversa. Esto mejora la resiliencia de la aplicación permitiendo que partes de la UI sigan funcionando incluso cuando otras fallan.

Modularidad y Resiliencia

Los boundaries a nivel de módulo son fundamentales para aplicaciones modulares. Permiten que cada módulo maneje sus propios errores de forma independiente, mejorando la mantenibilidad y la experiencia del usuario cuando ocurren fallos parciales.

Patrones de Error Boundaries

Existen varios patrones comunes para implementar error boundaries en JavaScript. Cada patrón tiene sus propios casos de uso y ventajas, y la elección del patrón adecuado depende de la arquitectura de tu aplicación y de los requisitos específicos.

Patrón de Fallback UI

El patrón de fallback UI muestra una interfaz alternativa cuando ocurre un error. Esto es especialmente útil en aplicaciones web donde quieres mantener al usuario informado cuando algo falla, en lugar de mostrar una pantalla en blanco o un error del navegador.

patron-fallback.js
Loading code...

Este ejemplo muestra el patrón de fallback UI. Cuando ocurre un error, el boundary captura el error y muestra una UI alternativa en lugar de colapsar. La función renderWithFallback intenta renderizar un componente, y si falla, muestra un mensaje de error amigable al usuario.

  • <strong>Mensaje de error claro</strong>: Explica qué sucedió en lenguaje simple
  • <strong>Botón de reintentar</strong>: Permite al usuario intentar la operación nuevamente
  • <strong>Enlace a soporte</strong>: Proporciona ayuda adicional si el error persiste
  • <strong>Estado de carga</strong>: Muestra un indicador mientras se reintenta

No Ocultes Errores

Aunque el patrón de fallback UI mejora la experiencia del usuario, no debes usarlo para ocultar errores. Siempre registra los errores para debugging y considera mostrar información detallada en modo desarrollo.

Patrón de Reintentos Automáticos

El patrón de reintentos automáticos intenta una operación fallida varias veces antes de declarar un error. Esto es útil para operaciones que pueden fallar temporalmente, como llamadas a APIs o conexiones a bases de datos.

patron-reintentos.js
Loading code...

Este ejemplo muestra el patrón de reintentos con backoff exponencial. La funciónwithRetry intenta una operación varias veces, incrementando el tiempo de espera entre intentos. Si todos los intentos fallan, lanza el error final. Este patrón es especialmente útil para operaciones de red que pueden fallar temporalmente.

Backoff Exponencial

El backoff exponencial incrementa el tiempo de espera entre reintentos exponencialmente (1s, 2s, 4s, 8s...). Esto evita sobrecargar el servidor cuando hay problemas temporales y aumenta las posibilidades de éxito en intentos posteriores.

Resumen: Error Boundaries

Conceptos principales:

  • Los error boundaries son patrones para capturar errores en niveles específicos
  • Se implementan con try/catch estratégicamente en diferentes capas
  • Los boundaries previenen que errores locales afecten toda la aplicación
  • Boundaries a nivel de función, módulo y aplicación para máxima resiliencia
  • Los boundaries permiten mostrar UI de fallback cuando ocurren errores

Mejores prácticas:

  • Usa boundaries a nivel de módulo para aplicaciones modulares
  • Implementa UI de fallback amigable para mejorar la experiencia del usuario
  • Usa reintentos con backoff exponencial para operaciones temporales
  • Registra siempre los errores para debugging, incluso dentro de boundaries
  • No uses boundaries para ocultar errores - siempre proporciona feedback