Desvendando os service workers: ciclo de vida e atualização

Desvendando os service workers: ciclo de vida e atualização
Neilton Seguins
Neilton Seguins

Compartilhe

Imagine que você está usando uma página web para acessar um banco de imagens, como Pinterest por exemplo.

De repente, sua conexão com a internet cai, e o aplicativo para de funcionar, interrompendo sua experiência e impossibilitando que você continue visualizando o site. Situações como essa são comuns e podem ser frustrantes para os(as) usuários(as).

A falta de suporte offline e carregamento lento são desafios que precisam ser resolvidos para melhorar a satisfação e experiência do usuário ao navegar na sua aplicação web.

E é aí que entram os service workers, os trabalhadores da web prontos a solucionar este problema. Então vamos conhecer e entender melhor sobre eles.

Neste artigo você irá aprender:

  • O que são Service Workers;
  • Para que servem;
  • Ciclo de vida;

E muito mais. Vamos lá?

O que é um service worker?

Usuários(as) de aplicativos web frequentemente enfrentam problemas de conectividade que interrompem o funcionamento dos aplicativos, levando a uma experiência insatisfatória.

Principalmente usuários(as) que acessam através de dispositivos móveis, como smartphones, que funcionam usando tecnologias de conexão 4G ou 3G.

A falta de suporte offline e carregamento lento são desafios que precisam ser resolvidos para melhorar a satisfação do(a) usuário(a).

A implementação de um Service Worker pode resolver esses problemas. Um Service Worker é um script que o navegador executa em segundo plano, no que chamamos de thread secundária, separado da página web, permitindo funcionalidades como cache offline, notificações push e sincronização em segundo plano. Eles atuam como intermediários entre o aplicativo web e a rede, possibilitando o cache de recursos para funcionamento offline e a resposta rápida às solicitações de rede.

Se quiser aprender na prática como trabalhar com threads e requisições simultâneas, recomendo fazer o curso JavaScript: trabalhando com threads para requisições simultâneas clicando aqui neste link.

Com essas características eles são perfeitos para que você consiga disponibilizar recursos de sua aplicação offline, como uma página inteira, para que o(a) usuário(a) saiba que ele está acessando uma versão offline da aplicação.

Você também pode enviar notificações em segundo plano, fazendo com que mesmo que o(a) usuário(a) não esteja na página ele receba novidades, promoções, informações e muito mais.Sabendo disso, vamos criar um service worker e entender melhor o seu ciclo de vida.

Banner promocional da Alura, com um design futurista em tons de azul, apresentando dois blocos de texto, no qual o bloco esquerdo tem os dizeres:

Ciclo de vida de um service worker

O ciclo de vida de um service worker é composto por três fases principais:

  1. Registro: etapa em que o service worker é registrado no navegador.
  2. Instalação: o service worker é baixado e instalado.
  3. Ativação: após a instalação, o service worker é ativado e assume o controle das requisições de rede.
  4. Operação: durante a operação, o service worker responde aos eventos, como fetch (requisição de rede) e push (notificações).

Para explicar cada etapa e deixar essa experiência mais prática, vou deixar o link de um projeto no github. Iremos criar e registrar um service worker neste projeto e a partir disso entender cada etapa de seu ciclo de vida. Vamos lá!

Etapa de registro

Antes da fase de instalação, deve ser feito o registro do service worker. Iremos fazer isso dentro de uma tag script, no arquivo index.html da nossa aplicação:

<script>
  if ("serviceWorker" in navigator) {
    navigator.serviceWorker
      .register("/service-worker.js")
      .then(function (registration) {
        console.log("Service Worker registrado com sucesso:", registration);
      })
      .catch(function (error) {
        console.log("Falha ao registrar o Service Worker:", error);
      });
  }
</script>

O arquivo service-worker.js é o arquivo onde você implementará toda a lógica do seu service worker e geralmente deve estar na pasta raíz do seu projeto.

Ao salvar esse arquivo e rodar a aplicação, você poderá observar na aba “Application > Service workers” do Chrome Dev Tools, o seguinte:

Imagem do Chrome Dev Tools, especificamente da aba de Application > Service workers, mostrando que o service worker foi instalado na aplicação e está ativo. Destaque para a caixa de Ciclo de atualização (Update Cycle) que mostra as etapas do ciclo de vida de um service worker, como a instalação, espera e ativação.

Isso significa que nosso service worker foi instalado com sucesso. Dentro da caixa de Update Cycle, podemos ver três fases, a de install, wait e activate, sendo respectivamente a fase de instalação, espera e ativação.

O navegador tenta fazer automaticamente as fases de instalação e espera assim que ele registra o service worker, mas podemos fazer algumas coisas nessas fases como veremos mais adiante.

Escopo

Na função register você consegue definir um objeto com a propriedade scope.

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js', { scope: "/src/" })
  // ...
}

O escopo de um service worker é determinado pela localização dele em um servidor da web.

Por exemplo, se um service worker for executado em uma página localizada em /src/index.html e estiver em /src/sw.js, o escopo dele será /src/ e você pode definir isso explicitamente com a propriedade scope.

O escopo limita quais páginas o service worker controla. Neste exemplo, isso significa que o service worker carregado de /src/sw.js só pode controlar páginas localizadas em /src/ ou na subárvore dele. Para saber mais clique aqui!

A menos que você tenha um bom motivo para limitar o escopo de seu service worker, deve registrá-lo na pasta raíz de seu projeto para que o escopo dele seja o mais amplo possível e ele tenha melhor controle sobre sua aplicação.

Nestes casos, não é necessário definir o escopo usando a propriedade scope, como fizemos acima.

Detalhe, quando dizemos que um service worker controla uma página, na verdade ele está controlando um cliente.

Um cliente é qualquer página aberta cujo URL esteja no escopo do service worker. Clique aqui para saber mais!

Etapa de instalação

Uma das funcionalidades mais poderosas dos service workers é a capacidade de armazenar recursos em cache, permitindo o acesso offline às aplicações web.

Para fornecer recursos offline de sua aplicação, você pode pré-cachear os arquivos, e isso é geralmente feito na etapa de instalação do service worker. No arquivo service-worker.js, vamos fazer o seguinte:

const cacheName = "meuCache";
const preCache = [
  "/index.html",
  "/styles.css",
  "/script.js",
  "/script-crud.js",
];

self.addEventListener("install", (event) => {
  self.skipWaiting();
  event.waitUntil(
    caches.open(cacheName).then((cache) => {
      return cache.addAll(preCache);
    })
  );
});

Vamos analisar:

  • Criamos um nome para o cache;
  • Criamos um array com os arquivos estáticos que queremos pré-cachear;
  • A linha self.skipWaiting() força o navegador a pular a fase de espera e ativar imediatamente o service worker;
  • Adicionamos um callback ao evento de install, para criar uma nova instância de Cache, e colocar lá os arquivos que queremos pré-cachear. Se a promisse para o waitUntill for resolvida com sucesso, o service worker adiciona esses arquivos em cache. Caso contrário, se a promisse for rejeitada, o service worker é descartado.

Você pode visualizar o cache que gerou na aba Application > Storage > Cache Storage do Chrome Dev Tools

Imagem do Chrome Dev Tools, especificamente da aba de Application > Storage > Cache storage, mostrando pré-cache gerado pelo service worker dos arquivos estáticos da aplicação contidos no array preCache no arquivo service-worker.js.

Realizar o pré-cache na etapa de instalação faz com que você consiga carregar recursos em suas aplicações de maneira bem mais rápida, sem depender da disponibilidade da rede para isso. Isso é muito útil em situações de baixa conexão. Se quiser saber mais sobre como usar estratégias de cache dá uma olhada na documentação neste link.

Etapa de ativação

Se tudo correr bem com as etapas de registro e instalação, o service worker entra na fase de “activating”.

Como vimos acima, podemos pular imediatamente a fase de espera e entrar no estado de “activate”, pulando a fase de espera e ativando o service worker imediatamente. Uma tarefa típica nesta etapa é remover os caches antigos, mas para um service worker novo isso não é muito relevante no momento.

Gerenciando atualizações no service worker

Gerenciar atualizações do service worker é fundamental para garantir que os(as) usuários(as) obtenham a versão mais recente do seu aplicativo web.

As atualizações do service worker ocorrem quando uma nova versão do arquivo do service worker é detectada.

O navegador verifica se há atualizações ao acessar a página onde o service worker está registrado. Se houver mudanças no arquivo, o navegador baixa a nova versão e inicia o processo de instalação e ativação.

Como as atualizações acontecem

Quando o navegador detecta uma nova versão do service worker, ele baixa o novo arquivo e começa o processo de instalação.

Durante a instalação, o novo service worker espera até que todos os ativos necessários sejam armazenados em cache. Após a instalação, ele aguarda até que o service worker anterior seja desativado. Só então ele é ativado e começa a controlar as requisições.

Durante essa ativação, é comum limpar caches antigos para liberar espaço e garantir que apenas os dados mais recentes sejam armazenados.

No código abaixo, ao ativar o novo service worker, ele acessa todas as chaves de cache existentes e remove aquelas que não estão em uma lista de permissões específica (neste caso, “MeuNovoCacheName_v2”):

self.addEventListener('activate', (event) => {
  const cacheAllowList = ['MeuNovoCacheName_v2'];

  event.waitUntil(
    caches.keys().then((keys) => {
      return Promise.all(keys.map((key) => {
        if (!cacheAllowList.includes(key)) {
          return caches.delete(key);
        }
      }));
    })
  );
});

Isso garante que caches antigos sejam removidos, prevenindo o excesso de armazenamento.

Depois que o cache antigo é removido, o novo service worker assume o controle da página, substituindo o antigo.

Se você se interessou em se aprofundar no ciclo de vida dos service workers, recomendo a leitura do artigo do Jake Archibald intitulado “O ciclo de vida do service worker” e disponível neste link.

Conclusão

Ao longo deste artigo, abordamos os principais aspectos dos service workers, desde sua definição básica até o ciclo de vida e como gerenciar atualizações.

Vimos que eles são uma ferramenta poderosa para melhorar a experiência do(a) usuário(a) ao permitir funcionalidades como cache offline, notificações push e sincronização em segundo plano.

Se você deseja mergulhar fundo nos service workers, recomendo ler a documentação do Chrome for developers, com muito conteúdo sobre ciclo de vida e estratégias de armazenamento em cache.

Que tal continuar seus estudos aprendendo mais sobre otimização e performance em suas aplicações React?

É exatamente isso que você irá aprender na Formação React: maximizando a performance de aplicações.

Tenho certeza que após fazer essa formação você será capaz de desenvolver sites muito mais performáticos e de ótimo desempenho com React.

Bons estudos e até a próxima!

Neilton Seguins
Neilton Seguins

Sou graduado como Bacharel em Ciência e Tecnologia e em Engenharia Mecânica. Atuo como Instrutor de Desenvolvedor de Software na Alura e possuo experiência com desenvolvimento usando JavaScript/TypeScript, React js, Next js e Node.js. Amo compartilhar conhecimento, pois acredito que a educação é transformadora e quero mudar a vida de pessoas através da educação assim como consegui mudar de vida. Também amo ouvir e tocar música, ler livros e mangás e assistir séries.

Veja outros artigos sobre Front-end