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 é necessário tomar medidas para garantir que a instalação inicial de um service worker não prejudique a experiência do usuário na primeira visita.

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

Boilerplate de registro comum

Se você já leu sobre service workers, provavelmente encontrou um modelo 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 de um registro de service worker anterior, como uma maneira de informar aos usuários que eles precisam atualizar a página. Mas essas são apenas variações menores das poucas linhas padrão de código.

Há alguma nuance em navigator.serviceWorker.register? Há alguma prática recomendada a seguir? Não é de surpreender (já que este artigo não termina aqui), a resposta para ambas é "sim".

A primeira visita de um usuário

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

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

Agora imagine que, no processo de download do JavaScript ou das imagens que a página precisa renderizar, o navegador decide iniciar uma linha de execução ou processo em segundo plano. Para simplificar, vamos supor que seja uma linha de execução. Suponha que você não esteja em uma máquina de desktop potente, mas sim no tipo de smartphone fraco que a maioria das pessoas considera como dispositivo principal. A criação desta linha de execução extra adiciona contenção para o tempo de CPU e a 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 em segundo plano inativa faça uma diferença significativa. Mas e se essa linha de execução não estiver ociosa, mas decidir que também vai começar a fazer o download de recursos da rede? Qualquer preocupação com a contenção de CPU ou memória deve ser deixada de lado para se preocupar com a largura de banda limitada disponível para muitos dispositivos móveis. A largura de banda é preciosa. Não prejudique os recursos importantes fazendo o download de recursos secundários ao mesmo tempo.

Tudo isso significa que iniciar uma nova linha de execução de worker de serviço para fazer o download e armazenar em cache os recursos em segundo plano pode prejudicar seu objetivo de oferecer a menor latência na experiência interativa na primeira vez que um usuário visita seu site.

Como melhorar o modelo

A solução é controlar a inicialização do worker de serviço escolhendo quando chamar navigator.serviceWorker.register(). Uma regra simples seria adiar o registro até que o load event seja acionado no window, como esta:

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 o app da Web está fazendo logo após o carregamento. Por exemplo, o app da Web do Google I/O 2016 tem uma animação curta antes da transição para a tela principal. Nossa equipe descobriu que iniciar o registro do service worker durante a animação pode causar instabilidade em dispositivos móveis de baixo custo. Em vez de oferecer uma experiência ruim aos usuários, atrasamos o registro do service worker até depois da animação, quando o navegador tinha mais chances de ficar alguns segundos ocioso.

Da mesma forma, se o app da Web usar um framework que realiza uma configuração adicional após o carregamento da página, procure um evento específico do framework que sinalize quando esse trabalho for concluído.

Visitas subsequentes

Até agora, nos concentramos na experiência da primeira visita, mas qual é o impacto do registro de service worker atrasado nas visitas repetidas ao site? Embora isso possa surpreender algumas pessoas, não deve 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 é iniciado antes de que a solicitação de todas as páginas no escopo dele seja feita, o que faz sentido quando você pensa nisso. Se o service worker atual não estiver em execução antes de visitar uma página, ele não terá a chance de atender aos eventos fetch para solicitações de navegação.

Assim, quando há um worker de serviço ativo, não importa quando você chama navigator.serviceWorker.register() ou, na verdade, se você o chama. A menos que você mude o URL do script do service worker, navigator.serviceWorker.register() será efetivamente um no-op durante as visitas subsequentes. Quando ele é chamado é irrelevante.

Motivos para se inscrever com antecedência

Há algum cenário em que faz sentido registrar o service worker o mais cedo possível? Um exemplo que vem à mente é quando o worker do serviço usa clients.claim() para assumir o controle da página durante a primeira visita, e o worker do serviço executa agressivamente o armazenamento em cache de tempo de execução no manipulador fetch. Nessa situação, há uma vantagem em ativar o service worker o mais rápido possível para tentar preencher os caches de execução com recursos que podem ser úteis mais tarde. Se o app da Web se enquadra nessa categoria, vale a pena dar um passo atrás para garantir que o gerenciador install do worker de serviço não solicite recursos que disputam a largura de banda com as solicitações da página principal.

Como testar

Uma ótima maneira de simular uma primeira visita é abrir seu app da Web em uma janela anônima do Chrome e analisar o tráfego de rede nas Ferramentas 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 revisitar seu site quando já há um service worker e caches totalmente preenchidos, você não tem a mesma experiência que um novo usuário teria, e é fácil ignorar um possível problema.

Confira um exemplo que ilustra a diferença que o tempo de registro pode fazer. As duas capturas de tela foram tiradas ao visitar um app de exemplo no modo de navegação anônima usando o estrangulamento 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 realizar o registro do service worker o mais rápido possível. É possível conferir solicitações de pré-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 mostrar 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é-cache não começam até que todos os recursos sejam buscados da rede, eliminando qualquer disputa por 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 worker de serviço sem precisar acessar a rede novamente.

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

Conclusão

Em resumo, garantir que os usuários tenham a melhor experiência na primeira visita deve ser uma prioridade. Atrasar o registro do service worker até que a página seja carregada durante a visita inicial pode ajudar a garantir isso. Você ainda vai ter todos os benefícios de ter um worker de serviço para suas visitas repetidas.

Uma maneira simples de atrasar o registro inicial do seu worker de serviço 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');
    });
}