Prácticas recomendadas para cronometrar tu registro de service worker.
Los service worker pueden acelerar significativamente las visitas repetidas a tu app web, pero debes tomar medidas para asegurarte de que la instalación inicial de un service worker no degrade la experiencia de primera visita de un usuario.
En general, aplazar el registro del service worker hasta después de que se haya cargado la página inicial brindará la mejor experiencia para los usuarios, especialmente aquellos que usen dispositivos móviles con conexiones de red más lentas.
Modelo común de registro
Si alguna vez leíste sobre los service workers, es probable que te encuentres con código estándar similar al siguiente:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js');
}
A veces, esto puede estar acompañado de algunas declaraciones console.log()
o un código que detecta una actualización de un registro de service worker anterior, como una forma de informar a los usuarios que deben actualizar la página. Pero esas son solo pequeñas variaciones
de las pocas líneas de código estándar.
navigator.serviceWorker.register
: ¿hay algún matiz? ¿Hay prácticas recomendadas a seguir? No es de extrañar (dado que este artículo no termina aquí), la respuesta a ambas preguntas es "sí".
La primera visita de un usuario
Consideremos la primera visita de un usuario a una app web. Aún no existe un service worker, y el navegador no tiene forma de saber con antelación si se instalará uno.
Como desarrollador, tu prioridad debe ser asegurarte de que el navegador obtenga rápidamente el conjunto mínimo de recursos críticos necesarios para mostrar una página interactiva. Cualquier elemento que demore la recuperación de esas respuestas es enemigo de una experiencia veloz de tiempo para interacción.
Ahora, imagina que, durante la descarga del código JavaScript o de las imágenes que necesita renderizar tu página, el navegador decide iniciar un proceso o un subproceso en segundo plano (para mayor brevedad, supondremos que se trata de un subproceso). Supongamos que no tienes una computadora de escritorio robusta, sino el tipo de teléfono celular con poca potencia que gran parte del mundo considera como su dispositivo principal. La inicialización de este subproceso adicional agrega contención del tiempo de CPU y la memoria, que tu navegador, de otro modo, podría dedicar a renderizar una página web interactiva.
Es poco probable que un subproceso en segundo plano inactivo haga una diferencia significativa. Pero ¿qué pasa si ese subproceso no está inactivo y, en su lugar, decide que también comenzará a descargar recursos de la red? Cualquier preocupación sobre la contención de la CPU o la memoria debería ocupar un segundo plano, debido al ancho de banda limitado que tienen muchos dispositivos móviles. El ancho de banda es un bien preciado, así que no descargues recursos secundarios al mismo tiempo, ya que debilitarás los recursos críticos.
Todo esto quiere decir que iniciar un nuevo subproceso de service worker para descargar y almacenar recursos en caché en segundo plano puede funcionar en contra de tu objetivo de proporcionar la experiencia interactiva más breve la primera vez que un usuario visita tu sitio.
Mejora el modelo
La solución es controlar el inicio del service worker. Para ello, debes elegir cuándo llamar a navigator.serviceWorker.register()
. Una regla general simple sería retrasar el registro hasta después de que load
event
se active en window
, de la siguiente manera:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js');
});
}
Sin embargo, el momento adecuado para iniciar el registro del service worker también puede depender de lo que haga tu app web inmediatamente después de que se carga. Por ejemplo, la app web de Google I/O 2016 muestra una animación breve antes de pasar a la pantalla principal. Nuestro equipo descubrió que si se inicia el registro del service worker durante la animación, se pueden generar bloqueos en los dispositivos móviles de gama baja. En lugar de brindar una mala experiencia a los usuarios, retrasamos el registro del service worker hasta después de la animación, cuando es más probable que el navegador tenga unos segundos de inactividad.
Del mismo modo, si tu aplicación web usa un framework que realiza una configuración adicional después de que se carga la página, busca un evento específico del framework que indique cuándo finalizó el trabajo.
Visitas posteriores
Hasta ahora, nos enfocamos en la experiencia de la primera visita, pero ¿qué impacto tiene el retraso del registro del service worker en las visitas repetidas a tu sitio? Aunque podría sorprender a algunas personas, no debería causar ningún impacto.
Cuando se registra un service worker, pasa por los eventos de ciclo de vida install
y activate
.
Una vez que se activa un service worker, puede controlar los eventos fetch
de las visitas posteriores a la app web. El service worker se inicia antes de que se realice la solicitud a cualquier página de su alcance, lo cual tiene sentido si lo piensas. Si el service worker existente no se ejecutara antes de visitar una página, no podría completar los eventos fetch
para las solicitudes de navegación.
Por lo tanto, una vez que haya un service worker activo, no importa cuándo llamas a navigator.serviceWorker.register()
o, de hecho, si lo llamas o no.
A menos que cambies la URL de la secuencia de comandos del service worker, navigator.serviceWorker.register()
es efectivamente una no-op durante las visitas posteriores. Cuando se lo llama
es irrelevante.
Motivos para registrarse antes de tiempo
¿Hay alguna situación en la que sea conveniente registrar el service worker lo antes posible? Uno que se me viene a la mente es cuando el service worker usa clients.claim()
para tomar el control de la página durante la primera visita y realiza un almacenamiento en caché en tiempo de ejecución de forma agresiva dentro de su controlador fetch
. En esa situación, hay una ventaja de activar el service worker lo antes posible, para tratar de propagar sus cachés en tiempo de ejecución con recursos que podrían ser útiles más adelante. Si
tu app web pertenece a esta categoría, vale la pena tomar distancia para asegurarte
de que el controlador install
del service worker no solicite
recursos que compitan por el ancho de banda con las solicitudes de la página principal.
Realizando pruebas
Una excelente manera de simular una primera visita es abrir la app web en una ventana de incógnito de Chrome y observar el tráfico de red en DevTools de Chrome. Como desarrollador web, es probable que vuelvas a cargar una instancia local de tu app web decenas y decenas de veces al día. Sin embargo, si vuelves a visitar tu sitio cuando ya hay un service worker y las cachés están propagadas por completo, no obtienes la misma experiencia que tendría un usuario nuevo y es fácil ignorar un posible problema.
A continuación, se incluye un ejemplo que ilustra la diferencia que podría marcar el momento del registro. Ambas capturas de pantalla se toman cuando visitas una app de ejemplo en modo Incógnito con limitación de red para simular una conexión lenta.
![Tráfico de red con registro anticipado.](https://web.dev/static/articles/service-workers-registration/image/network-traffic-early-re-63d00e80875ce.png?authuser=5&hl=es)
La captura de pantalla anterior muestra el tráfico de red cuando se modificó la muestra para realizar el registro del service worker lo antes posible. Puedes ver las solicitudes de almacenamiento previo en caché (las entradas que tienen el ícono de ajustes junto a ellas, que se originan en el controlador install
del service worker) intercaladas con solicitudes de otros recursos necesarios para mostrar la página.
![El tráfico de red con registro tardío](https://web.dev/static/articles/service-workers-registration/image/network-traffic-late-reg-17e31ea5d01ab.png?authuser=5&hl=es)
En la captura de pantalla anterior, el registro del service worker se retrasó hasta después de que se cargó la página. Puedes ver que las solicitudes de almacenamiento previo en caché no comienzan hasta que se recuperan todos los recursos de la red, lo que elimina cualquier contención por el ancho de banda. Además, debido a que algunos de los elementos que almacenamos previamente en caché ya están en la caché HTTP del navegador (los elementos con (from disk cache)
en la columna Tamaño), podemos propagar la caché del service worker sin tener que volver a la red.
Ganarás puntos adicionales si ejecutas este tipo de prueba en un dispositivo de gama baja y una red móvil real. Puedes aprovechar las funciones de depuración remota de Chrome para conectar un teléfono Android a tu máquina de escritorio por USB y asegurarte de que las pruebas que ejecutas realmente reflejen la experiencia real de muchos de tus usuarios.
Conclusión
En resumen, asegurarte de que los usuarios tengan la mejor experiencia de la primera visita debe ser una prioridad. Si retrasas el registro del service worker hasta que se cargue la página durante la primera visita, es posible que te sea más fácil hacerlo. De todas formas, obtendrás todos los beneficios de contar con un service worker para las visitas repetidas.
Una forma directa de garantizar que el registro inicial del service worker se retrase hasta después de que se haya cargado la primera página es usar la siguiente información:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/service-worker.js');
});
}