Registro do service worker

Práticas recomendadas para programar o registro do service worker.

Os service workers podem acelerar significativamente as visitas repetidas ao seu app da Web, mas você precisa tomar medidas para garantir que a instalação inicial de um service worker não prejudique a experiência do primeiro acesso do usuário.

Geralmente, adiar o registro do service worker até que a página inicial seja carregada para oferecer a melhor experiência para os usuários, especialmente aqueles em dispositivos móveis com conexões de rede mais lentas.

Código de registro comum

Se você já leu sobre service workers, provavelmente se deparou com boilerplate semelhante ao seguinte:

if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js');
}

Às vezes, isso pode ser acompanhado por algumas instruções console.log() ou código que detecta uma atualização no registro de um service worker anterior, como uma forma de permitir que os usuários atualizem a página. Mas essas são pequenas variações nas poucas linhas de código padrão.

Há alguma nuance em navigator.serviceWorker.register? Há alguma prática recomendada a seguir? Não surpreende que a resposta para as duas coisas seja "sim", já que este artigo não termina aqui.

A primeira visita do usuário

Vamos considerar a primeira visita de um usuário a um app da Web. Ainda não há service worker, e o navegador não tem como saber com antecedência se um service worker será instalado.

Como desenvolvedor, sua prioridade precisa ser garantir que o navegador receba rapidamente o conjunto mínimo de recursos críticos necessários para exibir uma página interativa. Qualquer coisa que atrasa a recuperação dessas respostas é inimigo de uma experiência rápida de interação.

Agora, imagine que, no processo de download do JavaScript ou das imagens que a página precisa para renderizar, o navegador decida iniciar uma linha de execução ou um processo em segundo plano (para simplificar, vamos presumir que é uma linha de execução). Suponha que você não esteja usando um computador superpoderoso, mas sim o tipo de smartphone menos potente que grande parte do mundo considera como o dispositivo principal. Ativar essa linha de execução extra aumenta a contenção do tempo de CPU e da memória que o navegador poderia gastar na renderização de uma página da Web interativa.

É improvável que uma linha de execução ociosa em segundo plano faça uma diferença significativa. Mas e se essa linha de execução não estiver inativa, mas decidir que também vai começar o download de recursos da rede? Qualquer preocupação com a contenção de CPU ou memória ficará abandonada por questões da largura de banda limitada disponível para muitos dispositivos móveis. A largura de banda é algo precioso, por isso, não atrapalhe os recursos críticos fazendo o download de recursos secundários ao mesmo tempo.

Tudo isso para dizer que ativar uma nova linha de execução de service worker para fazer o download e armazenar recursos em cache em segundo plano pode prejudicar seu objetivo de fornecer a experiência de interação mais curta na primeira vez que um usuário visitar seu site.

Como melhorar o boilerplate

A solução é controlar o início do service worker escolhendo quando chamar navigator.serviceWorker.register(). Uma regra prática simples é atrasar o registro até que load event seja disparado em window, desta forma:

if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js');
    });
}

No entanto, o momento certo para iniciar o registro do service worker também pode depender do que seu app da Web está fazendo logo após o carregamento. Por exemplo, o app da Web do Google I/O 2016 apresenta uma pequena animação antes de fazer a transição para a tela principal. Nossa equipe descobriu que iniciar o registro do service worker durante a animação pode levar à instabilidade em dispositivos móveis mais simples. Em vez de oferecer aos usuários uma experiência ruim, atrasamos o registro do service worker até depois da animação, quando o navegador provavelmente teria alguns segundos de inatividade.

Da mesma forma, se o app da Web usar um framework que faz outras configurações após o carregamento da página, procure um evento específico do framework que indique quando esse trabalho for concluído.

Visitas subsequentes

Estamos nos concentrando na experiência de primeira visita até agora, mas qual é o impacto do registro atrasado do service worker em visitas repetidas ao seu site? Embora isso possa surpreender algumas pessoas, não haverá nenhum impacto.

Quando um service worker é registrado, ele passa pelos eventos de ciclo de vida install e activate. Depois que um service worker é ativado, ele pode processar eventos fetch para todas as visitas subsequentes ao seu app da Web. O service worker começa antes de a solicitação de qualquer página no escopo dele ser feita, o que faz sentido quando você pensa sobre isso. Se o service worker já não estiver em execução antes de acessar uma página, ele não vai conseguir atender a eventos fetch para solicitações de navegação.

Portanto, quando há um service worker ativo, não importa quando você chama navigator.serviceWorker.register() ou, se você o chama. A menos que você altere o URL do script do service worker, navigator.serviceWorker.register() será um ambiente autônomo durante as visitas subsequentes. O momento da chamada é irrelevante.

Motivos para registrar com antecedência

Há algum cenário em que registrar o service worker o quanto antes é adequado? Uma que vem à mente é quando o service worker usa clients.claim() para assumir o controle da página durante a primeira visita e quando executa o armazenamento em cache no ambiente de execução de forma agressiva dentro do gerenciador fetch. Nessa situação, há uma vantagem em ativar o service worker o mais rápido possível, para tentar preencher os caches de ambiente de execução com recursos que podem ser úteis mais tarde. Caso seu app da Web se enquadre nessa categoria, vale a pena dar um passo atrás para garantir que o gerenciador install do service worker não solicite recursos que briguem por largura de banda com as solicitações da página principal.

Fazendo testes

Uma ótima maneira de simular um primeiro acesso é abrir o app da Web em uma janela anônima do Chrome e observar o tráfego de rede no DevTools do Chrome. Como desenvolvedor da Web, você provavelmente recarrega uma instância local do seu app da Web dezenas e dezenas de vezes por dia. No entanto, ao acessar seu site novamente quando já houver um service worker e caches totalmente preenchidos, você não terá a mesma experiência que um novo usuário teria, e é fácil ignorar um possível problema.

Este é um exemplo que ilustra a diferença que o momento do registro pode fazer. As duas capturas de tela foram feitas ao visitar um app de exemplo no modo de navegação anônima usando a limitação de rede para simular uma conexão lenta.

Tráfego de rede com registro antecipado.

A captura de tela acima reflete o tráfego de rede quando a amostra foi modificada para executar o registro do service worker o mais rápido possível. É possível ver as solicitações de pré-armazenamento em cache (as entradas com o ícone de engrenagem ao lado delas, originadas do gerenciador install do service worker) intercaladas com solicitações para os outros recursos necessários para exibir a página.

Tráfego de rede com registro tardio.

Na captura de tela acima, o registro do service worker foi adiado até que a página fosse carregada. As solicitações de pré-armazenamento em cache não são iniciadas até que todos os recursos tenham sido buscados na rede, eliminando qualquer contenção da largura de banda. Além disso, como alguns dos itens que estamos pré-armazenando em cache já estão no cache HTTP do navegador (os itens com (from disk cache) na coluna Tamanho), podemos preencher o cache do service worker sem ter que acessar a rede novamente.

Pontos extras se você executar esse tipo de teste em um dispositivo real e mais simples em uma rede móvel real. Você pode aproveitar os recursos de depuração remota do Chrome para conectar um smartphone Android à sua máquina desktop via USB e garantir que os testes executados realmente reflitam a experiência real de muitos dos seus usuários.

Conclusão

Para resumir, garantir que os usuários tenham a melhor experiência no primeiro acesso é a prioridade. Adiar o registro do service worker até que a página seja carregada durante a visita inicial pode ajudar a garantir isso. Você ainda terá todos os benefícios de um service worker nas visitas repetidas.

Uma maneira simples de garantir o atraso do registro inicial do seu service worker até que a primeira página seja carregada é usar o seguinte:

if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/service-worker.js');
    });
}