Tema representativo de entrevista

Entrevista de Frontend: ¿Cómo proteges los datos de formularios no guardados ante los cambios del ciclo de vida de la página?

FrontendDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Un formulario extenso pierde modificaciones cuando un navegador móvil congela o descarta su pestaña. ¿Cómo combinarías los eventos del ciclo de vida de la página, los borradores locales, el guardado en el servidor y la restauración de bfcache?

Planteamiento y contexto

Eres responsable de un formulario de solicitud de varios pasos. Los usuarios cambian de pestaña, bloquean el teléfono, navegan hacia atrás o abandonan la página durante horas. El navegador puede congelar la página, restaurarla desde bfcache o descartarla ante la presión de memoria. El formulario debe recuperar los borradores sin sobrescribir datos más recientes del servidor.

Asume que el formulario contiene datos confidenciales pero no regulados, que el usuario puede iniciar sesión en varios dispositivos y que el acceso a la red es intermitente. La respuesta debe especificar qué es de mejor esfuerzo y qué es autoritativo.

Qué evalúa el entrevistador

  • Si distingues entre visibilidad, congelamiento, descarte de página y restauración de bfcache.
  • Si evitas tratar unload o beforeunload como un hook de persistencia confiable.
  • Si los borradores locales tienen reglas de propiedad, versión, expiración y conflicto.
  • Si la recuperación preserva la intención del usuario sin reemplazar silenciosamente datos más nuevos del servidor.

Preguntas de clarificación antes de responder

  1. ¿Es aceptable perder un borrador local, o el producto debe ofrecer una garantía de recuperación duradera? Esto determina si el almacenamiento local es una conveniencia o solo una caché.
  2. ¿Puede editarse el mismo borrador en varios dispositivos? En caso afirmativo, el servidor necesita una política de versiones o de conflictos.
  3. ¿Es seguro almacenar los datos de forma local? Los campos sensibles pueden requerir cifrado, omisión selectiva o ninguna persistencia local.
  4. ¿Cuál es el contrato de envío (submit)? El guardado de un borrador y el envío final requieren reglas distintas de idempotencia y validación.

Estructura de respuesta en 30 segundos

“Trato al servidor como la fuente autoritativa y al borrador local como una caché de recuperación acotada. Persisto un borrador versionado ante cambios de entrada con debounce y realizo un envío de mejor esfuerzo cuando el documento pasa a estar oculto. Utilizo pageshow para revalidar tras la restauración de bfcache y resume para refrescar el estado obsoleto tras un congelamiento. Nunca dependo de unload. Cada borrador registra una expiración, versión del esquema, versión base del servidor y campos modificados; los conflictos se muestran o fusionan explícitamente en lugar de sobrescribirse silenciosamente.”

Análisis detallado paso a paso

1. Modelar los estados del ciclo de vida

visibilitychange informa a la página si pasó a estar oculta o visible; no promete que JavaScript continuará ejecutándose. Un navegador puede congelar una página oculta, y una página descartada puede no llegar a ejecutar código de limpieza. pagehide y pageshow describen la navegación y la restauración de bfcache, mientras que freeze y resume exponen las transiciones del ciclo de vida de Chromium.

Por lo tanto, el diseño guarda antes del riesgo, no durante un unload de último segundo. En la transición de visibilitychange a hidden, programa una pequeña escritura local y un envío de mejor esfuerzo por la red. En pagehide, detén el trabajo no esencial y registra un punto de control local. En pageshow, verifica event.persisted y revalida la versión del servidor antes de mostrar el formulario restaurado.

2. Hacer que el borrador local sea acotado y versionado

Almacena únicamente los campos cuya recuperación sea segura. Un registro de borrador puede contener:

text
draft_id, user_id, form_schema, base_server_version,
changed_at, expires_at, dirty_fields, values

Utiliza IndexedDB para datos estructurados y un índice local pequeño para búsquedas. Aplica debounce a las escrituras para que el tipeo no genere una escritura por cada pulsación de tecla, limita el tamaño de la carga útil y elimina los borradores expirados. Una versión de esquema permite a la aplicación migrar o descartar un registro incompatible en lugar de analizarlo como datos actuales.

El registro local no es una autoridad. Es una caché de usuario/dispositivo que puede faltar, estar desactualizada, duplicarse o ser eliminada por el navegador.

3. Enviar de forma segura cuando la página queda oculta

Cuando el documento pase a estar oculto, primero confirma el punto de control local y luego intenta una pequeña solicitud autenticada si el producto admite guardado en segundo plano. La solicitud incluye el ID del borrador y la versión del servidor en la que se basó. El servidor la acepta solo si la versión coincide y luego devuelve la nueva versión.

No bloquees la navegación con una solicitud prolongada. Si la solicitud no puede completarse, el punto de control local aún protege este dispositivo. Evita una solicitud sincrónica en unload: perjudica la navegación y no está garantizada en las rutas del ciclo de vida móvil.

4. Recuperar tras bfcache y congelamiento

Cuando pageshow se dispara con persisted, la página puede contener una instantánea visualmente completa pero lógicamente desactualizada. Consulta la versión actual del servidor, compárala con la versión base del formulario y muestra una opción de resolución de conflictos si otro dispositivo modificó el borrador. Cuando se dispare resume, refresca la sesión y los datos que pudieran haber expirado mientras la página estaba congelada.

Si la página fue descartada, no hay estado en memoria para reanudar. En la siguiente carga, busca un borrador local no expirado, compara su versión base con la del servidor y ofrece restaurar, descartar o fusionar. El usuario debe ver qué valores son más recientes antes de aceptar una fusión.

5. Probar rutas de falla y privacidad

Prueba el cambio de pestañas, el cambio de aplicación móvil, la navegación hacia atrás/adelante, la restauración de bfcache, el descarte por el navegador, las ediciones sin conexión, el agotamiento de cuota, la migración de esquemas, los borradores expirados y los conflictos entre dos dispositivos. Asegura que una versión más reciente del servidor nunca se sobrescriba silenciosamente.

Oculta los campos sensibles en los registros. Borra los borradores al eliminar la cuenta, respeta un período de retención corto y explica la recuperación local en el aviso de privacidad. Mide el éxito de la restauración, la tasa de conflictos, los fallos de escritura local y la latencia de guardado en el servidor; un indicador de “guardado” debe representar un punto de control conocido, no la esperanza de que se haya ejecutado un manejador de unload.

Respuesta de ejemplo de alta calidad

Haría que el servidor fuera la fuente de verdad versionada y mantendría un borrador local acotado para la recuperación. Los cambios de entrada se guardan con debounce en IndexedDB con una versión de esquema, expiración, conjunto de campos modificados y la versión del servidor utilizada como base. Cuando visibilitychange reporta oculto, escribo el punto de control e intento un guardado autenticado pequeño, pero no bloqueo la navegación ni dependo de unload.

En pageshow, especialmente cuando el evento provino de bfcache, vuelvo a consultar la versión del servidor antes de confiar en el formulario restaurado. En resume, refresco los datos y el estado de la sesión que pudieran haber expirado mientras estaba congelada. Una página descartada inicia desde una carga limpia y ofrece el borrador local no expirado. Si las versiones difieren, muestro una interfaz de conflicto o una fusión a nivel de campo; nunca sobrescribo silenciosamente la copia más reciente del servidor. Las pruebas cubren el descarte móvil, ediciones sin conexión, límites de cuota y conflictos entre dos dispositivos.

Errores comunes

  • Error: Guardar únicamente en beforeunloadPor qué falla: los navegadores móviles pueden terminar una página sin dispararlo y puede bloquear bfcache → Solución: crear puntos de control con las entradas y en transiciones a estado oculto.
  • Error: Tratar una página visible de bfcache como actualizada → Por qué falla: la instantánea puede contener un estado del servidor desactualizado → Solución: revalidar en pageshow y comparar versiones.
  • Error: Convertir el almacenamiento local en la autoridad → Por qué falla: puede borrarse, quedar obsoleto o no estar disponible → Solución: usar la versión del servidor y presentar los datos locales como candidatos de recuperación.
  • Error: Reintentar un formulario completo sobre una versión más nueva → Por qué falla: sobrescribe ediciones no relacionadas → Solución: enviar campos modificados con una versión optimista y resolver conflictos.
  • Error: Registrar valores del borrador para depuración → Por qué falla: se filtra contenido sensible en la telemetría → Solución: registrar únicamente IDs, versiones, tamaños y resultados.

Preguntas de seguimiento y respuestas

¿Debería usar localStorage o IndexedDB?

Usa localStorage solo para metadatos diminutos y sincrónicos. IndexedDB es adecuada para borradores estructurados, cargas útiles mayores y escrituras asincrónicas. Ninguno otorga durabilidad ni autoridad entre dispositivos; ambos requieren expiración, manejo de cuotas, control de versiones del esquema y reglas de privacidad.

¿Qué pasa si el usuario edita sin conexión en dos dispositivos?

Asigna a cada guardado una versión base del servidor y un ID de dispositivo o de borrador. Cuando se restablezca la conectividad, acepta únicamente una versión coincidente y luego muestra una fusión a nivel de campo o permite que el usuario elija. Una política de "el último cambio gana" es aceptable solo cuando el producto acepta explícitamente la pérdida silenciosa y los campos son independientes.

¿Puede un service worker garantizar el guardado final?

No. Un service worker puede mejorar la entrega de reintentos, pero puede detenerse, perder el acceso a la red o no estar disponible en un flujo particular. La UI debe reportar un punto de control confirmado y el servidor debe hacer que los reintentos sean idempotentes. El borrador local sigue siendo el mecanismo de respaldo para un dispositivo que no puede completar la solicitud.

Fuentes públicas

Preguntas relacionadas