Registro do service worker

Práticas recomendadas para determinar o momento de registro dos service workers.

Os service workers podem acelerar bastante as visitas repetidas ao seu app da Web. No entanto, você deve adotar algumas medidas para garantir que a instalação inicial do service worker não prejudique a experiência do usuário no primeiro acesso.

Geralmente, atrasar o registro do service worker até a página inicial ser carregada fornece a melhor experiência aos usuários, principalmente nos dispositivos móveis, que normalmente têm conexões de rede mais lentas.

Código comum de registro

Se você já tiver lido sobre os service workers, provavelmente se deparou com código clichê muito parecido com o seguinte:

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

Às vezes, esse código pode ser acompanhado de algumas declarações console.log() ou código que detecta uma atualização no registro de um service worker anterior, como uma forma de informar aos usuários que eles precisam atualizar a página. Mas essas são variações pequenas das poucas linhas de código padrão.

Então, há alguma mudança no navigator.serviceWorker.register? Existem práticas recomendadas a seguir? Não surpreende que a resposta seja "sim" para ambos (considerando que este artigo não acaba aqui)!

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á service worker, e o navegador não tem como saber antecipadamente se um service worker será instalado.

Como desenvolvedor, sua prioridade deve ser garantir que o navegador receba rapidamente o mínimo de recursos críticos necessário para exibir uma página interativa. Tudo que atrasar o recebimento dessas respostas prejudica a experiência de oferecer interação superrápido.

Agora, imagine que no processo de fazer o download do JavaScript ou das imagens de que sua página precisa para renderizar, o navegador decida iniciar um encadeamento ou processo em segundo plano (para tornar o exemplo mais rápido, digamos que seja um encadeamento). Suponha que você não esteja usando um computador superrápido, mas sim um celular simples que a maior parte do mundo considera como o dispositivo principal. Colocar esse thread extra para trabalhar gera 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.

Um thread ocioso em segundo plano provavelmente não faria uma grande diferença. Mas e se esse thread não estiver ocioso, mas sim decidir que vai começar a fazer o download de recursos da rede? Toda a preocupação com a contenção de CPU ou memória seria colocada de lado por conta das questões de largura de banda limitada de muitos dispositivos móveis. 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 significa que colocar um novo thread de service worker para fazer o download e armazenar recursos em cache em segundo plano pode ir contra seu objetivo de fornecer a experiência com a disponibilização da interação mais rápida possível na primeira vez que o usuário acessar seu site.

Como aprimorar o código clichê

A solução é controlar o início do service worker decidindo quando chamar navigator.serviceWorker.register(). Uma regra geral simples seria atrasar o registro até que a load event seja disparada em window, assim:

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

Mas o momento certo para iniciar o registro do service worker também pode depender do que o app da Web faz logo após o carregamento. Por exemplo, o app da Web do Google I/O 2016 apresenta uma animação curta antes de realizar a transição para a tela principal. Nossa equipe descobriu que iniciar o registro do service worker durante a animação pode levar a travamentos em dispositivos móveis mais simples. Em vez de dar aos usuários uma experiência ruim, atrasamos o registro do service worker até a animação acabar, quando a probabilidade de o navegador ter alguns segundos de ociosidade é maior.

Da mesma forma, se o app da Web usar uma biblioteca que faz uma configuração adicional depois que a página é carregada, procure um evento específico da estrutura que sinaliza quando esse trabalho for concluído.

Visitas subsequentes

Estávamos concentrados na experiência de primeiro acesso até agora, mas qual é o impacto do adiamento do registro do service worker nos acessos repetidos ao seu site? Embora isso possa surpreender algumas pessoas, não há impacto algum.

Quando um service worker é registrado, ele passa pelos eventos de ciclo de vida do install e do activate. Quando um service worker é ativado, ele pode gerenciar eventos fetch para todos os acessos subsequentes ao app da Web. O service worker é iniciado antes da solicitação de qualquer página feita dentro do escopo, o que faz sentido se você pensar bem. Se o service worker atual não estiver em execução antes do acesso a uma página, ele não terá a chance de atender aos eventos fetch de solicitações de navegação.

Por isso, quando há um service worker ativo, não importa quando você chama navigator.serviceWorker.register() nem se você de fato faz essa chamada. A menos que você mude o URL do script do service worker, navigator.serviceWorker.register() é, na prática, uma não operação durante visitas subsequentes. O momento em que ele é chamado é irrelevante.

Motivos para registrar com antecedência

Existe algum cenário em que registrar o service worker o quanto antes é uma boa ideia? Uma delas é quando o service worker usa clients.claim() para assumir o controle da página durante a primeira visita, e quando ele realiza de forma agressiva um armazenamento em cache no ambiente de execução dentro do gerenciador fetch. Nesse caso, 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 no futuro. Se o app da Web se enquadrar nessa categoria, vale a pena dar um passo para trás para garantir que o gerenciador de install do service worker não solicite recursos que briguem por largura de banda com as solicitações da página principal.

Testar

Uma ótima forma de simular um primeiro acesso é abrir o app da Web em uma janela anônima do Chrome e analisar o tráfego de rede no Chrome DevTools. Como desenvolvedor da Web, você provavelmente atualiza uma instância local do seu app da Web muitas e muitas vezes ao dia. Mas ao acessar seu site novamente, onde já há um service worker e caches totalmente preenchidos, você não passa pela mesma experiência que um novo usuário, e por isso fica fácil ignorar um possível problema.

Confira um exemplo que ilustra a diferença que o momento do registro pode fazer. As duas capturas de tela foram tiradas durante o acesso a um app de exemplo no modo de navegação anônima usando 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 o exemplo foi modificado para realizar o registro do service worker o quanto antes. É possível identificar solicitações de pré-armazenamento em cache (as linhas com o ícone de engrenagem ao lado delas, originadas pelo gerenciador install do service worker) intercaladas com solicitações de outros recursos necessários para exibir a página.

Tráfego de rede com registro posterior.

Na captura de tela acima, o registro do service worker foi adiado até que a página fosse carregada. É possível notar que as solicitações de pré-armazenamento em cache não são iniciadas até que todos os recursos tenham sido buscados da rede, eliminando toda 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 precisar acessar a rede novamente.

Palmas para você se você executa esse tipo de teste em um dispositivo simples que representa o mundo real em uma rede móvel real. Você pode aproveitar os recursos de depuração remota do Chrome para conectar um smartphone Android ao seu computador desktop via USB e garantir que os testes executados realmente reflitam a experiência da maioria dos seus usuários no mundo real.

Conclusão

Para resumir, garantir que os usuários tenham a melhor experiência possível no primeiro acesso é a prioridade nº 1. Adiar o registro de service workers até que a página seja totalmente carregada durante a visita inicial pode ajudar. Você ainda terá todos os benefícios de um service worker para acessos repetidos.

Se quiser uma forma simples de garantir o adiamento do registro inicial do seu service worker até que a primeira página seja toda carregada, use o seguinte:

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