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é que a página inicial seja carregada oferece a melhor experiência para os usuários, principalmente aqueles em dispositivos móveis com conexões de rede mais lentas.

Se você já tiver lido sobre os service workers, provavelmente se deparou com um modelo muito parecido com este:

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 nuances para navigator.serviceWorker.register? Existem práticas recomendadas a seguir? Não surpreende que a resposta para ambos seja "sim", porque este artigo não termina 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 atrasa o recebimento dessas respostas prejudica a experiência de interação rápida.

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. Ativar essa 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.

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 memória e CPU 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 escolhendo 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 à instabilidade em dispositivos móveis mais simples. Em vez de dar aos usuários uma experiência ruim, atrasamos o registro do service worker até depois da animação, 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 do ciclo de vida de install e activate. Quando um service worker é ativado, ele pode processar 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 estava em execução antes de acessar uma página, ele não teria a chance de atender eventos fetch para 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ê altere o URL do script do service worker, navigator.serviceWorker.register() será efetivamente um ambiente autônomo durante as visitas subsequentes. O momento em que é chamado é irrelevante.

Motivos para registrar com antecedência

Existe algum cenário em que o registro do service worker o mais cedo possível faz sentido? 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 maneira de simular uma primeira visita é abrir seu app da Web em uma janela anônima do Chrome e observar o tráfego da rede no DevTools do Chrome. 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 feitas ao visitar 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 a amostra foi modificada para executar o registro do service worker o mais rápido possível. É 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 mostrar 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 seja carregada. Observe que 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 por largura de banda. Além disso, como alguns dos itens que estamos 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.

Você vai ganhar ponto se realizar esse tipo de teste em um dispositivo simples e real em uma rede móvel real. Aproveite os recursos de depuração remota do Chrome para conectar um smartphone Android à sua máquina desktop por USB e garantir que os testes em execução reflitam a experiência real de muitos dos usuários.

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 quando em um acesso inicial pode ajudar. Você ainda terá todos os benefícios de ter um service worker para suas visitas repetidas.

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');
    });
}