Tema representativo de entrevista

¿Cómo se coordina el trabajo compartido entre pestañas con la Web Locks API?

FrontendDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Una aplicación web puede tener varias pestañas abiertas, pero solo una debería actualizar los datos de la caché compartida y ejecutar la sincronización a la vez. Diseña la coordinación con la Web Locks API y explica el alcance, la gestión de colas, ifAvailable, AbortSignal, los cierres inesperados de pestañas y los navegadores no compatibles.

1. Planteamiento

Varias pestañas del mismo origen pueden actualizar una caché de IndexedDB y sincronizarse con el servidor al mismo tiempo. Diseña un coordinador que permita que como máximo un contexto se sincronice mientras los demás esperan, omiten el proceso o vuelven a verificar tras la liberación. Cubre el cierre de pestañas, los errores de red y los navegadores sin soporte para Web Locks.

2. Restricciones y aclaraciones

  • El nombre de un bloqueo se comparte entre ventanas y workers del mismo origen.
  • Un bloqueo solo protege el alcance de coordinación del callback asíncrono; no es una transacción de base de datos ni un control de concurrencia del lado del servidor.
  • La sincronización puede tardar, por lo que requiere cancelación, reintentos y la difusión de una versión o resultado.
  • Distingue entre esperar por un bloqueo, sondear de inmediato y abandonar una solicitud.

3. Enfoque principal

Llama a navigator.locks.request(name, options, callback) para solicitar un bloqueo con nombre. El bloqueo se libera después de que se resuelve la Promise del callback, por lo que este debe contener el flujo completo de lectura, sincronización y escritura de estado. Una solicitud predeterminada se encola; ifAvailable: true ejecuta el callback con null cuando está ocupado; signal puede cancelar una solicitud que todavía está en espera.

El administrador de bloqueos libera un bloqueo cuando el contexto que lo posee finaliza, pero la corrección no debe depender únicamente de la limpieza por cierre inesperado de pestañas. Los registros de sincronización deben incluir una versión, un contrato de arrendamiento (lease) o una clave de idempotencia, y el servidor aún debe validar las escrituras. Otras pestañas pueden conocer una nueva versión a través de BroadcastChannel o volviendo a leer IndexedDB.

4. Implementación de referencia

javascript
const LOCK = "shared-cache-sync";

async function runSync(signal) {
  return navigator.locks.request(LOCK, { signal }, async (lock) => {
    if (!lock) return { status: "busy" };
    const current = await readSyncVersion();
    if (await isFresh(current)) return { status: "fresh" };
    const result = await fetchAndWriteCache({ signal, baseVersion: current });
    await publishVersion(result.version);
    return { status: "updated", version: result.version };
  });
}

async function trySyncWithoutWaiting() {
  return navigator.locks.request(
    LOCK,
    { ifAvailable: true },
    (lock) => lock ? runOneSync() : { status: "busy" },
  );
}

5. Corrección y manejo de fallos

El bloqueo proporciona exclusión mutua entre contextos del mismo origen para el recurso nombrado; no revierte una solicitud de red ni una escritura en la base de datos. Vuelve a leer la versión antes de una actualización condicional. Si la red falla, lanza un error para que el bloqueo se libere y una solicitud posterior pueda reintentar. No almacenes un booleano de tipo "poseemos el bloqueo" fuera del callback.

Cuando un AbortSignal cancela una solicitud en espera, los invocadores deben distinguir la cancelación de una falla de negocio. Para esperas prolongadas, muestra que otra pestaña se está sincronizando u omite el trabajo; tras la liberación, vuelve a leer la versión para evitar actualizaciones duplicadas. Una notificación por BroadcastChannel es una optimización; IndexedDB o el servidor siguen siendo la fuente de verdad.

6. Preguntas de seguimiento y errores comunes

  • Web Locks solo coordina contextos del mismo origen; no puede bloquear otro sitio, un proceso del servidor o una fila de la base de datos.
  • ifAvailable no se encola. Una solicitud ocupada recibe null, lo cual es un resultado normal.
  • steal: true rompe la semántica habitual de colas y debe limitarse a tareas explícitamente descartables con verificaciones de versión.
  • Sin la API, BroadcastChannel junto con IndexedDB pueden proporcionar una coordinación de mejor esfuerzo, pero no la misma garantía de exclusión mutua; el servidor todavía necesita deduplicación.

7. Lecturas adicionales

Compara Web Locks, transacciones de IndexedDB, mensajes de Service Worker y BroadcastChannel: los bloqueos proporcionan exclusión entre contextos, las transacciones brindan atomicidad en una sola base de datos y los canales proporcionan notificaciones. La exclusión entre dispositivos o entre usuarios corresponde a leases en el servidor, APIs idempotentes o restricciones de bases de datos.

8. Criterios de evaluación en entrevistas

Capacidad para definir el alcance del bloqueo

El candidato debe indicar que un bloqueo con nombre coordina ventanas y workers del mismo origen, se libera cuando la Promise del callback se resuelve y no puede reemplazar el control de concurrencia del servidor o de la base de datos.

Capacidad para distinguir los modos de solicitud

Debe explicar el encolamiento predeterminado, el sondeo inmediato con ifAvailable y el abandono de una espera mediante AbortSignal.

Capacidad para gestionar cierres inesperados y duplicados

Debe utilizar versiones, claves de idempotencia y escrituras condicionales, explicando que la limpieza por el cierre inesperado de una pestaña no revierte las escrituras de negocio.

Capacidad para proponer una alternativa de fallback realista

Debe proporcionar una ruta de mejor esfuerzo con BroadcastChannel/IndexedDB y señalar que la exclusión mutua es más débil, por lo que las protecciones en el servidor siguen siendo obligatorias.

Fuentes públicas

Preguntas relacionadas