Tema representativo de entrevista

Entrevista de Frontend: ¿Cómo diseñarías una navegación de SPA recuperable con la Navigation API?

FrontendDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

¿Cómo rediseñarías la capa de navegación de una SPA para que sea recuperable y observable sin romper el historial del navegador? Explica las condiciones de carrera en la carga, la recuperación de errores, la restauración del desplazamiento y el mecanismo alternativo cuando la Navigation API no está disponible.

Planteamiento y contexto

¿Cómo rediseñarías la capa de navegación de una SPA para que sea recuperable y observable sin romper el historial del navegador? Explica las condiciones de carrera en la carga, la recuperación de errores, la restauración del desplazamiento y el mecanismo alternativo cuando la Navigation API no está disponible.

Esta pregunta es adecuada para roles de frontend, full-stack y plataforma web. Evalúa el modelo de navegación del navegador, las máquinas de estado asíncronas y la mejora progresiva en lugar de la memorización de configuraciones de frameworks. La Navigation API proporciona una vista unificada de la navegación en el mismo documento a través de eventos como navigate, navigatesuccess y navigateerror, además de intercept(). No reemplaza las cargas iniciales renderizadas en el servidor ni modifica el límite de seguridad de la navegación entre documentos.

Qué evalúan los entrevistadores

  • Tratar la URL y la entrada del historial como estado de navegación, no solo como memoria del componente.
  • Distinguir las rutas en el mismo documento de documentos completos, descargas, formularios y enlaces de distinto origen.
  • Manejar peticiones obsoletas, cancelaciones, errores y la navegación hacia atrás/adelante.
  • Definir reglas para la restauración del desplazamiento, el foco y el estado de la página.
  • Mantener operativos la primera carga y los navegadores no compatibles.
  • Instrumentar el éxito, el fallo, el tiempo de espera, la cancelación y la recuperación.

Una respuesta en 30 segundos

«Mantendría operativos los puntos de entrada renderizados en el servidor y los enlaces normales, con la URL y el historial como fuente de verdad. Cuando la Navigation API esté disponible, interceptaría únicamente las rutas de aplicación del mismo origen, iniciaría una carga cancelable en el evento navigate y permitiría que una navegación más reciente cancele a una anterior. Solo la tarea actual puede confirmar la vista. En caso de éxito, restauro el desplazamiento y el foco; en caso de fallo, mantengo la vista anterior y ofrezco reintentar o recargar. Los navegadores no compatibles utilizan la ruta existente de la History API, compartiendo el mismo cargador y métricas».

Solución paso a paso

Paso 1: Delimitar las navegaciones que se interceptan

Comprueba si el destino es del mismo origen, una ruta de aplicación y seguro de renderizar en el documento actual. Los enlaces externos, las descargas, los destinos de distinto origen, los protocolos especiales y la semántica de formularios deben conservar el comportamiento predeterminado del navegador. La primera petición de documento sigue perteneciendo al servidor y al navegador; un evento navigate no puede hacer que la carga de un script fallido sea recuperable por sí mismo.

Llama a intercept() únicamente para una ruta de aplicación aprobada. El manejador carga datos, actualiza la vista y aplica la política de desplazamiento. Para cualquier otro destino, permite que el navegador navegue normalmente. Esto preserva la semántica de los enlaces y evita convertir la navegación de la plataforma en una máquina de estados accidental que solo existe en el cliente.

Paso 2: Hacer que la navegación sea cancelable

Asigna un número de secuencia incremental a cada navegación y pasa su AbortSignal a los cargadores de datos. Si un usuario pasa de /search?q=a a /search?q=ab, una respuesta tardía de la primera petición no debe sobrescribir la segunda. Antes de confirmar, comprueba que la señal no haya sido abortada, que la secuencia sea la actual y que el destino aún coincida con el estado previsto.

js
let latestNavigation = 0;

navigation.addEventListener("navigate", (event) => {
  if (!event.canIntercept || !isAppRoute(event.destination.url)) return;
  const id = ++latestNavigation;
  event.intercept({
    async handler() {
      const data = await loadRoute(event.destination.url, event.signal);
      if (event.signal.aborted || id !== latestNavigation) return;
      renderRoute(data);
    }
  });
});

El ejemplo muestra la regla de condiciones de carrera, no un enrutador completo. El código de producción aún necesita errores del cargador, tiempos de espera, aciertos de caché y desmontaje de componentes. «La última respuesta gana» es incorrecto porque el orden de finalización de la red no representa la intención más reciente del usuario.

Paso 3: Confirmar historial, desplazamiento y estado de la página

Tras una navegación exitosa, confirma la URL de destino como resultado. Si un valor recuperable pequeño pertenece a la entrada actual del historial, updateCurrentEntry() puede almacenarlo; los objetos grandes y los datos sensibles no deben guardarse allí. La política de desplazamiento debe distinguir entre una nueva ruta, atrás/adelante y un ancla: las nuevas rutas suelen comenzar en la parte superior, mientras que el recorrido por el historial restaura la posición guardada.

Evita cambiar el título, el elemento seleccionado o las migas de pan al inicio de una carga a menos que la UI represente explícitamente un estado pendiente. Confirma el estado visual principal tras el éxito y mantén el contenido anterior con una acción de reintento tras el fallo. navigatesuccess y navigateerror son puntos de observación útiles para métricas de latencia, cancelación y fallos.

Paso 4: Recuperarse de errores

La página anterior debe seguir siendo utilizable cuando falla la carga. Proporciona acciones de reintento, retroceso y recarga completa, y distingue entre fallos de autenticación, autorización, recursos inexistentes y errores temporales de red. Si un destino requiere una respuesta de documento completa, deja de interceptar y permite que el navegador la maneje.

Si el estado del cliente o la ejecución de scripts se rompen, los enlaces normales y las rutas del servidor aún deben reconstruir la página desde la URL. No hagas que la recuperación dependa de una caché en memoria. Registra el destino, la secuencia de navegación, la clase de error y si ocurrió una alternativa para que «la dirección cambió pero la página anterior permaneció» sea diagnosticable.

Paso 5: Aplicar mejora progresiva

El soporte para Navigation API es más reciente que la History API base, por lo que no puede ser la única vía. Detecta window.navigation y los métodos que realmente utilizas, luego selecciona la ruta mejorada. Los navegadores no compatibles deben reutilizar el mismo cargador de rutas a través de la History API existente o el enrutador del framework; no bifurques las reglas de negocio solo por compatibilidad.

Prueba la primera carga, la recarga, atrás/adelante, los enlaces interrumpidos y los fallos de scripts en ambas vías de capacidad. Incluye redes lentas, navegación rápida, enlaces de distinto origen y descargas. La detección de capacidades debe estar cerca del uso de la funcionalidad en lugar de depender de una lista frágil de versiones del navegador.

Paso 6: Verificar el rendimiento y la accesibilidad

Utiliza tareas reales: búsqueda, filtrado, atrás, recarga, enlaces profundos y reintentos. Mide el tiempo hasta que sea interactivo, la tasa de cancelación, la tasa de fallos, la tasa de alternativas y las peticiones duplicadas, agrupadas por capacidad del navegador. El tiempo de renderizado de los componentes por sí solo no puede explicar los fallos de datos, permisos o historial.

Mantén la semántica nativa de los enlaces, el comportamiento del teclado y el movimiento de foco accesible. Después de una navegación interceptada, actualiza el título del documento y mueve el foco al contenido principal; no impidas abrir un enlace en una pestaña nueva. El almacenamiento en caché puede reducir la latencia, pero no debe ser la única fuente a partir de la cual una página pueda recuperarse.

Ganancia de información y límites

La distinción útil es que la Navigation API une los eventos de navegación de la plataforma, el historial y la carga cancelable en una sola cadena de estado. No hace que una fuente de datos sea confiable ni convierte una página de distinto origen en una ruta del mismo documento. Una respuesta sólida en una entrevista establece el límite de intercepción, el punto de confirmación, el comportamiento de la vista anterior ante fallos y el comportamiento predeterminado cuando el navegador carece de la funcionalidad.

Respuesta modelo

«Clasificaría la navegación en rutas de aplicación del mismo origen, documentos completos, descargas, formularios y destinos de distinto origen, e interceptaría solo la primera clase. Los puntos de entrada del servidor y los enlaces ordinarios siguen siendo válidos, con la URL y el historial como fuente de verdad. Con la Navigation API, el evento navigate llama a intercept() y genera un número de secuencia junto con una señal de cancelación. Una navegación más reciente cancela la carga anterior y el resultado se confirma solo si sigue siendo el actual.

Tras el éxito, actualizo la vista, el título, el foco y la política de desplazamiento. Una nueva ruta comienza en la parte superior; atrás y adelante restauran la posición en el historial. Un estado pequeño y recuperable puede usar la entrada del historial actual, mientras que los datos grandes o sensibles permanecen en otro lugar. En caso de fallo, mantengo la vista anterior, ofrezco reintentar, volver o recargar por completo, y registro la latencia, la cancelación y la clase de error a través de eventos de navegación y registros del servidor.

Si la Navigation API no está disponible, el mismo cargador se ejecuta mediante la History API o el enrutador del framework; los enlaces externos y las descargas siempre utilizan el comportamiento predeterminado del navegador. Verificaría enlaces profundos, recargas, clics rápidos, redes lentas, enlaces de distinto origen, fallos de scripts y tareas con tecnología de asistencia para garantizar que la dirección, el contenido, el foco y el historial nunca entren en desacuerdo. El resultado es una capa de navegación progresiva en lugar de un reemplazo exclusivo del cliente que solo funcione en navegadores nuevos».

Errores comunes

  • Interceptar todos los enlaces → se rompen descargas, formularios y la semántica de distinto origen → intercepta únicamente rutas de aplicación aprobadas del mismo origen.
  • Dejar que la última respuesta gane → datos obsoletos pueden sobrescribir la intención actual → utiliza cancelaciones y comprobaciones de secuencia.
  • Probar solo el renderizado → los fallos de datos, permisos e historial permanecen ocultos → prueba la tarea de navegación completa y su recuperación.
  • Tratar la Navigation API como infraestructura de primera carga → la recarga o el fallo de scripts se vuelven irrecuperables → mantén las respuestas del servidor y los enlaces normales.
  • Poner todo el estado en las entradas del historial → las entradas se vuelven excesivamente grandes o exponen datos sensibles → almacena solo estados pequeños y reconstruibles.
  • Duplicar la lógica de negocio para la alternativa de respaldo → las rutas mejorada y alternativa divergen → comparte cargadores, reglas de estado y métricas.

Preguntas de seguimiento

¿Qué ocurre si una petición obsoleta ya pobló la caché?

Se pueden permitir las escrituras en caché, pero las confirmaciones de UI aún requieren una secuencia actual y una señal no abortada. Indexa las entradas por URL, parámetros y versión. Un resultado tardío puede preparar una petición futura, pero no debe mutar la página actual.

¿Debería un fallo de autorización regresar atrás o redirigir al inicio de sesión?

Utiliza estados del servidor explícitos para distinguir entre usuarios no autenticados, no autorizados y recursos inexistentes. Un usuario no autenticado puede entrar al inicio de sesión con una URL de retorno; un usuario no autorizado necesita una explicación y una siguiente acción segura. No disfraces la autorización como un error genérico de red.

¿Cómo se prueban los navegadores sin Navigation API?

Ejecuta las mismas tareas de enlaces profundos, recarga, atrás/adelante, red lenta y fallos mediante la detección de capacidades, comprobando la URL, el contenido, el título, el foco y el desplazamiento. Lo que importa es la paridad de comportamiento; las secuencias de eventos internas no necesitan ser idénticas.

¿Por qué no depender completamente de un enrutador de framework?

Se puede reutilizar un enrutador de framework, pero la respuesta debe definir el límite del navegador: qué navegaciones se mantienen nativas, cuáles se pueden mejorar y cómo se asignan las cancelaciones, el historial y los errores a los eventos del framework. Comienza desde la semántica de la plataforma y luego describe el adaptador.

Fuentes públicas

Preguntas relacionadas