API do Service Worker

Essencialmente, um service worker se comporta como um servidor proxy situado entre uma aplicação web, o navegador e a rede (quando esta estiver disponível). Eles servem, dentre outras coisas, para possibilitar a criação de experiências offline eficientes, interceptar requisições de rede – agindo adequadamente de acordo com o status atual da conexão – e atualizar os assets que residem no servidor. Service workers também permitem o acesso às APIs de push notification e background sync.

Service worker - Conceitos e uso

Um service worker é um tipo especial de worker baseado em eventos, o qual é registrado para um determinado path e origem. Na prática, ele é um arquivo JavaScript que pode controlar as páginas do site ao qual ele está associado, interceptando e modificando requisições e a navegação em si. Ele também faz cache dos recursos trafegados de maneira bastante granular, visando oferecer controle total sobre como a sua aplicação se comporta em determinadas situações (o exemplo mais óbvio, naturalmente, é quando não há conexão de rede disponível).

Assim como outros tipos de worker, um service worker é executado em um contexto isolado. Dessa forma, não tem acesso ao DOM e roda em uma thread completamente separada, sendo incapaz de realizar operações blocantes. Service workers foram projetados para ser totalmente assíncronos; como consequência disso, não permitem o acesso a APIs como XHR síncrono e localStorage.

Por questões de segurança, service workers funcionam apenas em sites servidos via HTTPS. A possibilidade de modificar requisições em um domínio desprotegido contra ataques do tipo man-in-the-middle seria desastrosa. No Firefox, é vetado o acesso à API de service workers para sites abertos no Modo de navegação privativa.

Nota: Os service workers superaram tentativas anteriores de resolver problemas semelhantes, como o AppCache. Há uma explicação simples para eles terem sido bem-sucedidos: Service workers não tentam adivinhar o que você está tentando fazer e, muito menos, deixam de funcionar caso não tenham adivinhado corretamente. Pelo contrário, você tem o controle milimétrico de tudo.

Nota: Service workers fazem uso intenso de promessas, uma vez que eles têm de esperar por respostas assíncronas para, após retornadas, poderem executar a ação apropriada (de sucesso ou erro). A arquitetura de promessas é ideal para esse tipo de cenário.

Registrando

O registro inicial de um service worker é feito através do método ServiceWorkerContainer.register(). Se bem-sucedido, seu service worker será descarregado no cliente e então ocorrerá a tentativa de instalação/ativação para as URLs acessadas pelo usuário sob a origem registrada ou, caso deseje, apenas dentro de um subconjunto limitado por você.

Download, instalação e ativação

Nesse estágio, seu service worker seguirá o seguinte ciclo de vida:

  1. Download
  2. Instalação
  3. Ativação

Quando o usuário acessa pela primeira vez um site ou página controlado por um service worker, ele é descarregado imediatamente.

Após isso, serão feitos novos downloads em intervalos de aproximadamente 24 horas. O download pode ocorrer mais frequentemente, mas ele precisa ser feito a cada 24 horas para prevenir que scripts ruins sejam um problema por períodos muito extensos.

A tentativa de instalação é feita sempre que o arquivo descarregado é identificado como novo – seja por diferir dos service workers pré-existentes (é feita uma comparação binária nessa etapa) ou por ser o primeiro descoberto para a página ou site em questão.

Na primeira vez que um service worker é disponibilizado, é feita a tentativa de instalação. Se bem-sucedida, ele é ativado.

Se, por outro lado, já existe um service worker pré-instalado para uma página ou site e for disponibilizada uma nova versão, ela será descarregada, mas não imediatamente ativada. Isso é chamado de worker em espera. Só será efetuada a ativação da versão atualizada quando não houver mais páginas utilizando a anterior. Após isso, ele passa a ser o worker ativo. Caso necessário, é possível pular a etapa de espera com o método ServiceWorkerGlobalScope.skipWaiting(). Em seguida, o novo worker ativo pode reivindicar as páginas existentes usando Clients.claim().

Você pode adicionar um listener para o evento InstallEvent. Uma ação padrão, quando esse evento é disparado, é preparar o seu service worker para ser utilizado (por exemplo: criado um cache usando a API de storage nativa e armazenando nela os assets que você quer que permaneçam disponíveis caso a aplicação fique offline).

Há também o evento activate. O momento em que ele é disparado é geralmente o ideal para limpar caches antigos e outras coisas associadas com a versão anterior do seu service worker.

Seu service worker pode responder a requisições usando o FetchEvent. Você pode manipular a resposta a essas requisições da maneira que quiser, através do método FetchEvent.respondWith.

**Nota:**Como oninstall e onactivate podem demorar a serem concluídos, a especificação de service workers disponibiliza um método waitUntil. Ele recebe como parâmetro uma promessa, notificando o navegador que há trabalho em andamento até que aquela promessa seja resolvida. O navegador, portanto, não deverá encerrar o service worker durante esse período de espera.

Para um tutorial completo, mostrando como construir seu primeiro exemplo do zero, leia Usando Service Workers.

Outras ideias de usos possíveis

  • Sincronização de dados em background
  • Responder a requisições de recursos a partir de outras origens
  • Receber de forma centralizada atualizações para dados de cálculo mais custoso, como geolocalização ou giroscópio, de forma a permitir que múltiplas páginas façam uso de um único conjunto de dados.
  • No lado do cliente, fazer compilação e gerenciamento de dependências para CoffeeScript, LESS, módulos CommonJS/AMD, entre outros.
  • Hooks para serviços em background.
  • Templates customizados com base em certos padrões de URL.
  • Melhorias de performance como, por exemplo, fazer o pré-carregamento de recursos que o usuário provavelmente irá precisar a curto prazo, como as próximas fotos de um álbum.

No futuro, service workers serão capazes de fazer várias outras coisas úteis para a plataforma web, deixando-a mais próxima de apps nativos em.

É interessante mencionar que outras especificações podem e irão passar a usar o contexto de service workers, por exemplo:

  • Sincronização em background: Iniciar um service worker mesmo quando não há usuários no site, de forma que o cache possa ser atualizado;
  • Reagir a mensagens push: Iniciar um service worker para enviar uma mensagem aos usuários dizendo que há conteúdo novo disponível;
  • Reagir a uma data/hora específica;
  • Entrar em uma geo-fence.

Interfaces

Cache

Representa o armazenamento para os pares de objeto Request e Response, os quais são cacheados como parte do ciclo de vida do ServiceWorker.

CacheStorage

Representa o armazenamento para objetos Cache. Ele disponibiliza um diretório-mestre com todos os caches nomeados que um ServiceWorker pode acessar, mantendo o mapeamento de nomes para os objetos Cache correspondentes.

Client

Representa o escopo do cliente de um service worker. Um cliente pode ser um documento no contexto de um navegador ou um SharedWorker, o qual é controlado por um worker ativo.

Clients

Representa o container para uma lista de objetos Client. É a principal forma de acessar os clientes na origem atual para o service worker ativo.

ExtendableEvent

Estende a vida dos eventos install e activate disparados no ServiceWorkerGlobalScope, como parte do ciclo de vida do service worker. Isso garante que qualquer evento funcional (como o FetchEvent) não seja despachado para o ServiceWorker até que ele conclua as ações em andamento, como por exemplo: atualizar esquemas de banco de dados, apagar caches defasados, etc.

ExtendableMessageEvent

O objeto de evento do message, o qual é disparado em um service worker (quando uma mensagem de canal é recebida no ServiceWorkerGlobalScope a partir de outro contexto) — estende o tempo de vida desses eventos.

FetchEvent

O parâmetro recebido no handler ServiceWorkerGlobalScope.onfetch. O FetchEvent representa uma ação de descarregamento que é despachada no ServiceWorkerGlobalScope de um ServiceWorker. Ele contém informações sobre a requisição e a resposta resultante, além de disponibilizar o método FetchEvent.respondWith(), o qual nos permite devolver uma resposta customizada para a página que está sendo controlada.

InstallEvent

O parâmetro recebido no handler oninstall. A interface InstallEvent representa uma ação de instalação que é despachada no ServiceWorkerGlobalScope de um ServiceWorker. Como deriva do ExtendableEvent, ele assegura que eventos funcionais, como o FetchEvent, não sejam despachados durante a instalação.

Disponibiliza métodos para gerenciar o pré-carregamento de recursos com um service worker.

Retornar um objeto ServiceWorkerContainer, o qual permite accesso ao registro, remoção, atualização e comunicação com os objetos ServiceWorker para o documento associado.

NotificationEvent

O parâmetro recebido no handler onnotificationclick. A interface NotificationEvent representa um evento de click em uma notificação que é despachado no ServiceWorkerGlobalScope de um ServiceWorker.

ServiceWorker

Representa um service worker. Diferentes contextos de navegação (ex: páginas, workers, etc.) podem ser associados com o mesmo objeto ServiceWorker.

ServiceWorkerContainer

Disponibiliza um objeto representando o service worker como uma unidade global no ecossistema de rede, incluindo métodos para registrar, desregistrar e atualizar service workers, além de poder acessar o status de cada worker e seus registros.

ServiceWorkerGlobalScope

Representa o contexto de execução global de um service worker.

ServiceWorkerMessageEvent Deprecated

Representa uma mensagem enviada a um ServiceWorkerGlobalScope. Vale ressaltar que essa interface está defasada em navegadores modernos. As mensagens de service worker agora usam a interface MessageEvent para manter consistência com outras funcionalidades de messageria da web.

ServiceWorkerRegistration

Representa o registro de um service worker.

ServiceWorkerState Experimental

Associado com o estado do ServiceWorker.

SyncEvent Non-standard

A interface SyncEvent representa uma ação de sincronização que é despachada no ServiceWorkerGlobalScope de um ServiceWorker.

SyncManager Non-standard

Disponibiliza uma interface para registrar e listar registros de sincronização.

WindowClient

Representa o escopo de um cliente de service worker que é um documento em um contexto de navegador, o qual é controlado por um worker ativo. Esse é um tipo especial de objeto Client, como alguns métodos e propriedades adicionais disponíveis.

Especificações

Specification
Service Workers

Compatibilidade com navegadores

Veja também