Can’t make the #ChromeDevSummit this year? Catch all the content (and more!) on the livestream, or join your peers for a CDS Extended event at a hosted location nearby. To learn more, check out the Chrome Dev Summit 2019 website.

Registro dos service workers

Os service workers podem aumentar bastante a velocidade das 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 ao registro de um service worker anterior, como uma forma de permitir que os usuários atualizem a página. Mas essas são variações pequenas das poucas linhas de código que normalmente se usa.

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)!

O primeiro acesso do usuário

Vamos analisar o primeiro acesso do 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). Presuma que você não esteja usando um computador superrápido, mas sim um celular bem simples que a maior parte do mundo usa como o principal dispositivo. Colocar esse thread adicional 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 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 acessórios ao mesmo tempo.

Mencionamos tudo isso para dizer 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é depois do evento "load" disparar 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 assim que carrega. Por exemplo, o app da Web do Google I/O 2016 apresenta uma animação curta antes de realizar uma 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.

Seguindo o mesmo princípio, 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.

Acessos 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 alguns, não há impacto algum.

Quando um service worker é registrado, ele passa por install e activate eventos do ciclo de vida. 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 seu escopo, o que faz sentido se você pensar bem. Se o service worker existente 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 altere o URL do script do service worker, navigator.serviceWorker.register() é, na prática, uma "não operação" em acessos 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? Quando o service worker usa clients.claim() para assumir o controle da página durante o primeiro acesso, e quando ele realiza de forma agressiva um armazenamento em cache no ambiente de execução dentro de um gerenciador de fetch. Nesse caso, há uma vantagem em ativar o service worker o mais rápido possível: para tentar preencher seus 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 a fim de 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 e alinhar tudo

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

Veja um exemplo que demonstra 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 o 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, originadas pelo gerenciador de 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 seja 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 estamos pré-armazenando em cache alguns itens que já estão no cache HTTP do navegador — os itens com (from disk cache) na coluna "Size" —, podemos preencher o cache do service worker sem ter que recorrer à rede de novo.

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 celular Android ao seu computador desktop via USB e garantir que os testes realizados 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 quando em um acesso 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');
  });
}

Feedback

Was this page helpful?
Yes
What was the best thing about this page?
It helped me complete my goal(s)
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It had the information I needed
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It had accurate information
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It was easy to read
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
Something else
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
No
What was the worst thing about this page?
It didn't help me complete my goal(s)
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It was missing information I needed
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It had inaccurate information
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It was hard to read
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
Something else
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.