Os prestadores de serviços são poderosos e valem absolutamente a pena aprender. Eles permitem que você entregue um nível de experiência totalmente novo aos seus usuários. O seu site pode ser carregado instantaneamente. Ele pode funcionar offline. Ele pode ser instalado como uma aplicação nativa e sentir-se tão polido – mas com o alcance e liberdade da web.
Mas os trabalhadores de serviços são diferentes de qualquer coisa a que a maioria de nós, desenvolvedores web, estão acostumados. Eles vêm com uma curva de aprendizado íngreme e um punhado de trunfos que você tem que ficar atento.
Google Developers e eu recentemente colaboramos em um projeto -Service Workies – um jogo gratuito para entender os trabalhadores de serviços. Enquanto o construía e trabalhava com os complexos dentro e fora dos trabalhadores de serviços, deparei-me com alguns problemas. O que mais me ajudou foi a criar uma mão-cheia de metáforas ilustrativas. Neste post vamos explorar esses modelos mentais e envolver nossos cérebros em torno dos traços paradoxais que tornam os trabalhadores de serviços ao mesmo tempo complicados e incríveis.
- O mesmo, mas diferente #
- Uma nova camada #
- Poderoso, mas limitado #
- De longa, mas de curta duração #
- Stopped #
- esperar até #
- Vigilância para o estado global #
- Conjuntamente, mas separado #
- Messing with another service worker’s caches #
- Skip skipWaiting #
- Start clean #
- End clean #
- Mentalidade de trabalhadores de serviços #
O mesmo, mas diferente #
Apesar de codificar o seu trabalhador de serviços, muitas coisas vão se sentir familiares. Você pode usar seus recursos favoritos da nova linguagem JavaScript. Você ouve os eventos do ciclo de vida tal como nos eventos da UI. Você gerencia o fluxo de controle com promessas como você está acostumado.
Mas o comportamento de outros funcionários de serviço faz você coçar a cabeça em confusão. Especialmente quando você atualiza a página e não vê suas mudanças de código aplicadas.
Uma nova camada #
Normalmente, ao construir um site você tem apenas duas camadas para pensar: o cliente e o servidor. O service worker é uma nova camada que fica no meio.
Pense no seu service worker como uma espécie de extensão de browser-uma extensão que o seu site pode instalar no browser do seu utilizador. Uma vez instalado, o técnico de manutenção estende o navegador para o seu site com uma poderosa camada intermediária. Esta camada de service worker pode interceptar e tratar todos os pedidos que o seu site faz.
A camada de service worker tem o seu próprio ciclo de vida independente da tabulação do browser. Uma simples atualização de página não é suficiente para atualizar um funcionário do serviço – assim como você não esperaria uma atualização de página para atualizar o código implantado em um servidor. Cada camada tem suas próprias regras exclusivas para atualização.
No jogo Service Workies nós cobrimos os muitos detalhes do ciclo de vida do service worker e lhe damos uma tonelada de prática trabalhando com ele.
Pense no seu service worker como uma nova camada intermediária com seu próprio ciclo de vida e métodos para atualização.
Poderoso, mas limitado #
Acontecer um service worker no seu site lhe dá benefícios incríveis. O seu site pode:
- trabalhar sem falhas mesmo quando o usuário está offline
- obter melhorias maciças de desempenho através do cache
- usar notificações push
- ser instalado como um PWA
Com tanto quanto os trabalhadores de serviço podem fazer, eles são limitados pelo design. Eles não podem fazer nada síncrono ou na mesma linha do seu site. Isso significa que não podem acessar:
- localStorage
- the DOM
- the window
A boa notícia é que há um punhado de maneiras que sua página pode se comunicar com seu funcionário de serviço, incluindo direta postMessage
, Canais de Mensagens um-para-um e Canais de Transmissão um-para-muitos.
Pense no seu funcionário de serviço como algo que vive fora de sua página. Você pode falar com ele, mas ele não pode acessar sua página diretamente.
De longa, mas de curta duração #
Um funcionário de serviço ativo continua vivendo mesmo depois que um usuário deixa seu site ou fecha a aba. O navegador mantém esse funcionário de serviço por perto para que ele esteja pronto na próxima vez que o usuário voltar ao seu site. Antes da primeira solicitação ser feita, o técnico de serviço tem a chance de interceptá-la e assumir o controle da página. Isto é o que permite que um site funcione offline- o service worker pode servir uma versão em cache da própria página, mesmo que o usuário não tenha conexão com a internet.
No Service Workies visualizamos este conceito com Kolohe (um service worker amigável) interceptando e manipulando solicitações.
Stopped #
Embora os service workers pareçam imortais, eles podem ser parados a qualquer momento. O navegador não quer desperdiçar recursos em um prestador de serviços que atualmente não está fazendo nada. Ser interrompido não é a mesma coisa que ser interrompido – o trabalhador de serviços permanece instalado e ativado. É apenas colocado para dormir. Da próxima vez que for necessário (por exemplo, para lidar com uma requisição), o navegador o acorda de volta.
esperar até #
Por causa da constante possibilidade de ser colocado para dormir, o seu técnico de serviço precisa de uma maneira de deixar o navegador saber quando está fazendo algo importante e não tem vontade de tirar uma soneca. É aqui que event.waitUntil()
entra em jogo. Este método prolonga o ciclo de vida em que é usado, impedindo que seja interrompido e que passe para a fase seguinte do seu ciclo de vida até que estejamos prontos. Isto nos dá tempo para configurar caches, buscar recursos da rede, etc.
Este exemplo diz ao navegador que nosso servidor de serviços não está pronto para instalar até que o cache assets
tenha sido criado e preenchido com a imagem de uma espada:
self.addEventListener("install", event => {
event.waitUntil(
caches.open("assets").then(cache => {
return cache.addAll();
})
);
});
Vigilância para o estado global #
Quando este start/stop acontece, o escopo global do servidor de serviços é redefinido. Então tenha cuidado para não usar nenhum estado global no seu service worker ou você ficará triste na próxima vez que ele acordar e tiver um estado diferente do que estava esperando.
Considere este exemplo que usa um estado global:
const favoriteNumber = Math.random();
let hasHandledARequest = false;
self.addEventListener("fetch", event => {
console.log(favoriteNumber);
console.log(hasHandledARequest);
hasHandledARequest = true;
});
Em cada solicitação este service worker irá registrar um número – digamos 0.13981866382421893
. A variável hasHandledARequest
também muda para true
. Agora o funcionário do serviço fica um pouco parado, então o navegador a pára. Da próxima vez que houver uma requisição, o técnico de serviço é necessário novamente, então o navegador a acorda. Seu script é avaliado novamente. Agora hasHandledARequest
é resetado para false
, e favoriteNumber
é algo completamente diferente-0.5907281835659033
.
Você não pode confiar no estado armazenado em um prestador de serviços. Além disso, criar instâncias de coisas como Canais de Mensagens pode causar bugs: você terá uma instância novinha em folha toda vez que o funcionário do serviço parar/ iniciar.
Aviso: Este problema é especialmente importante para ter em mente enquanto trabalha no código do seu servidor, porque quando o Chrome DevTools está aberto, o comportamento start/stop é desativado. Você pode até mesmo não ver bugs causados por confiar no estado global até que eles sejam enviados para seus usuários.
No capítulo 3 do Service Workies visualizamos nosso funcionário de serviço parado como perdendo toda a cor enquanto ele espera para ser acordado.
Pense no seu funcionário de serviço como um cachorro chicote. É rápido, leal e espectacular. Vai ficar ao seu lado, não importa o que aconteça. Mas principalmente só quer dormir. A toda a hora. Tens de o avisar quando quiseres que ele fique acordado. Bom cão!
Conjuntamente, mas separado #
A tua página só pode ser controlada por um trabalhador de serviço de cada vez. Mas pode ter dois trabalhadores de serviço instalados ao mesmo tempo. Quando você faz uma alteração no código do seu funcionário de serviço e atualiza a página, você não está realmente editando o seu funcionário de serviço. Os prestadores de serviços são imutáveis. Em vez disso, você está fazendo um novinho em folha. Este novo funcionário de serviço (vamos chamá-lo SW2) será instalado, mas ainda não será ativado. Ele tem que esperar que o service worker atual (SW1) termine (quando o seu usuário sair do seu site).
Messing with another service worker’s caches #
Enquanto instalando, o SW2 pode obter coisas setup-usually criando e populando caches. Mas atenção: este novo funcionário de serviço tem acesso a tudo a que o funcionário de serviço atual tem acesso. Se você não tiver cuidado, seu novo funcionário de serviço em espera pode realmente bagunçar as coisas para o seu atual funcionário de serviço. Alguns exemplos que podem causar-lhe problemas:
- SW2 podem apagar uma cache que o SW1 está usando ativamente.
- SW2 pode editar o conteúdo de uma cache que o SW1 está usando, fazendo com que o SW1 responda com ativos que a página não está esperando.
Skip skipWaiting #
Um funcionário de serviço também pode usar o arriscado método skipWaiting()
para assumir o controle da página assim que ela for feita a instalação. Isto geralmente é uma má idéia a menos que você esteja intencionalmente tentando substituir um funcionário de serviço de bugs. O novo service worker pode estar usando recursos atualizados que a página atual não está esperando, levando a erros e bugs.
Start clean #
A maneira de evitar que os seus service workers se ataquem uns aos outros é ter certeza de que eles usam caches diferentes. A maneira mais fácil de fazer isso é versionar os nomes de cache que eles usam.
const version = 1;
const assetCacheName = `assets-${version}`;
self.addEventListener("install", event => {
caches.open(assetCacheName).then(cache => {
// confidently do stuff with your very own cache
});
});
Quando você implanta um novo funcionário de serviço, você vai bater o version
para que ele faça o que precisa com um cache totalmente separado do funcionário de serviço anterior.
End clean #
Quando o seu funcionário de serviço chega ao estado activated
, você sabe que ele assumiu, e o funcionário de serviço anterior é redundante (ou seja, não é mais necessário). Neste ponto é importante limpar depois do antigo técnico de serviço. Ele não só respeita os limites de armazenamento do cache dos seus usuários, mas também pode evitar bugs não intencionais.
O método caches.match()
é um atalho frequentemente utilizado para recuperar um item de qualquer cache onde há uma correspondência. Mas itera através das caches na ordem em que foram criadas. Então digamos que você tem duas versões de um arquivo de script app.js
em dois caches diferentes-assets-1
e assets-2
. Sua página está esperando o script mais novo que está armazenado em assets-2
. Mas se você não apagou o cache antigo, caches.match('app.js')
vai devolver o antigo de assets-1
e muito provavelmente quebrar o seu site.
Tudo o que é preciso para limpar depois dos trabalhadores de serviço anteriores é apagar qualquer cache que o novo trabalhador de serviço não precise:
const version = 2;
const assetCacheName = `assets-${version}`;
self.addEventListener("activate", event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== assetCacheName){
return caches.delete(cacheName);
}
});
);
});
);
});
Prevenir que os seus trabalhadores de serviço se dêem mal uns aos outros requer um pouco de trabalho e disciplina, mas vale a pena o trabalho.
Pense na combinação do seu trabalhador de serviço e do seu site como um aplicativo instalável. Cada versão deve funcionar. Cada versão deve ser separada das outras. Imagine como seria um buggy num jogo se o desenvolvedor acidentalmente liberasse um patch que usasse uma nova lógica de jogo, mas ativos desatualizados. Você ficaria furioso nos fóruns tão rápido! Mantenha suas versões de aplicativos arrumadas & limpo.
Mentalidade de trabalhadores de serviços #
Introduzir a mentalidade correta enquanto pensa em trabalhadores de serviços irá ajudá-lo a construir a sua com confiança. Uma vez que você pegar o jeito deles, você será capaz de criar experiências incríveis para seus usuários.
Se você quiser entender tudo isso jogando um jogo, então você está com sorte! Vá jogar Service Workies onde você aprenderá as maneiras do trabalhador de serviço para matar as bestas offline.