Armazenamento em cache

O armazenamento em cache é uma ferramenta poderosa. Isso torna seus apps menos dependentes das condições de rede. Com um bom uso dos caches, é possível disponibilizar o app da Web off-line e veicular os recursos o mais rápido possível em qualquer condição de rede. Como mencionado em Recursos e dados, você pode decidir a melhor estratégia para armazenar em cache os recursos necessários. Para gerenciar o cache, seu worker de serviço interage com a API Cache Storage.

Browser Support

  • Chrome: 43.
  • Edge: 16.
  • Firefox: 41.
  • Safari: 11.1.

Source

A API Cache Storage está disponível em diferentes contextos:

  • O contexto da janela (linha de execução principal do PWA).
  • O service worker.
  • Qualquer outro worker que você usa.

Uma das vantagens de gerenciar o cache usando service workers é que o ciclo de vida dele não está vinculado à janela, o que significa que você não está bloqueando a linha de execução principal. Para usar a API Cache Storage, a maioria desses contextos precisa estar em uma conexão TLS.

O que armazenar em cache

A primeira pergunta que você pode ter sobre o armazenamento em cache é o que armazenar em cache. Embora não haja uma única resposta para essa pergunta, você pode começar com todos os recursos mínimos necessários para renderizar a interface do usuário.

Esses recursos precisam incluir:

  • O HTML da página principal (start_url do seu app).
  • Folhas de estilo CSS necessárias para a interface principal do usuário.
  • Imagens usadas na interface do usuário.
  • Arquivos JavaScript necessários para renderizar a interface do usuário.
  • Dados, como um arquivo JSON, necessários para renderizar uma experiência básica.
  • Fontes da Web.
  • Em um aplicativo com várias páginas, outros documentos HTML que você quer exibir rapidamente ou enquanto estiver off-line.

Pronto para off-line

Embora a capacidade de funcionar off-line seja um dos requisitos de um app da Web progressivo, é essencial entender que nem todo PWA precisa de uma experiência off-line completa, por exemplo, soluções de jogos em nuvem ou apps de criptoativos. Portanto, é aceitável oferecer uma interface básica para orientar os usuários nessas situações.

A PWA não deve renderizar uma mensagem de erro do navegador informando que o mecanismo de renderização da Web não conseguiu carregar a página. Em vez disso, use o worker de serviço para mostrar suas próprias mensagens, evitando um erro genérico e confuso do navegador.

Há muitas estratégias de armazenamento em cache diferentes que podem ser usadas, dependendo das necessidades da sua PWA. Por isso, é importante projetar o uso do cache para oferecer uma experiência rápida e confiável. Por exemplo, se todos os recursos do app forem transferidos rapidamente, não consumirem muito espaço e não precisarem ser atualizados em cada solicitação, o armazenamento em cache de todos os recursos será uma estratégia válida. Por outro lado, se você tiver recursos que precisam ser a versão mais recente, talvez seja melhor não armazenar esses recursos em cache.

Como usar a API

Use a API Cache Storage para definir um conjunto de caches na origem, cada um identificado com um nome de string que você pode definir. Acesse a API pelo objeto caches, e o método open permite a criação ou abertura de um cache já criado. O método "open" retorna uma promessa para o objeto de cache.

caches.open("pwa-assets")
.then(cache => {
  // you can download and store, delete or update resources with cache arguments
});

Como fazer o download e armazenar recursos

Para solicitar que o navegador faça o download e armazene os recursos, use os métodos add ou addAll. O método add faz uma solicitação e armazena uma resposta HTTP, e addAll um grupo de respostas HTTP como uma transação baseada em uma matriz de solicitações ou URLs.

caches.open("pwa-assets")
.then(cache => {
  cache.add("styles.css"); // it stores only one resource
  cache.addAll(["styles.css", "app.js"]); // it stores two resources
});

A interface de armazenamento de cache armazena a totalidade de uma resposta, incluindo todos os cabeçalhos e o corpo. Por isso, é possível recuperá-lo mais tarde usando uma solicitação HTTP ou um URL como chave. Você vai aprender a fazer isso no capítulo "Servir".

Quando armazenar em cache

No PWA, você é responsável por decidir quando armazenar arquivos em cache. Embora uma abordagem seja armazenar o maior número possível de recursos quando o service worker for instalado, geralmente não é a melhor ideia. Armazenar em cache recursos desnecessários desperdiça largura de banda e espaço de armazenamento e pode fazer com que o app forneça recursos desatualizados indesejados.

Não é necessário armazenar todos os recursos em cache de uma vez. É possível armazenar recursos em cache várias vezes durante o ciclo de vida da sua PWA, como:

  • Na instalação do service worker.
  • Após o primeiro carregamento da página.
  • Quando o usuário navega para uma seção ou rota.
  • Quando a rede está inativa.

É possível solicitar o armazenamento em cache de novos arquivos na linha de execução principal ou no contexto do worker de serviço.

Armazenar recursos em cache em um service worker

Um dos cenários mais comuns é armazenar em cache um conjunto mínimo de recursos quando o worker de serviço é instalado. Para isso, use a interface de armazenamento de cache no evento install no service worker.

Como a linha de execução do worker de serviço pode ser interrompida a qualquer momento, é possível solicitar que o navegador aguarde o término da promessa addAll para aumentar a oportunidade de armazenar todos os recursos e manter a consistência do app. O exemplo a seguir demonstra como fazer isso usando o método waitUntil do argumento de evento recebido no listener de eventos do service worker.

const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", event => {
   event.waitUntil(
      caches.open("pwa-assets")
      .then(cache => {
         return cache.addAll(urlsToCache);
      });
   );
});

O método waitUntil() recebe uma promessa e pede ao navegador que aguarde a resolução da tarefa na promessa (cumprida ou com falha) antes de encerrar o processo do worker de serviço. Talvez seja necessário encadear promessas e retornar as chamadas add() ou addAll() para que um único resultado chegue ao método waitUntil().

Também é possível processar promessas usando a sintaxe assíncrona/de espera. Nesse caso, você precisa criar uma função assíncrona que possa chamar await e retornar uma promessa para waitUntil() após a chamada, como no exemplo a seguir:

const urlsToCache = ["/", "app.js", "styles.css", "logo.svg"];
self.addEventListener("install", (event) => {
   let cacheUrls = async () => {
      const cache = await caches.open("pwa-assets");
      return cache.addAll(urlsToCache);
   };
   event.waitUntil(cacheUrls());
});

Solicitações entre domínios e respostas opacas

O PWA pode fazer o download e armazenar em cache recursos da origem e de domínios diferentes, como conteúdo de CDNs de terceiros. Com um app entre domínios, a interação do cache é muito semelhante às solicitações de mesma origem. A solicitação é executada e uma cópia da resposta é armazenada no cache. Assim como outros recursos em cache, ele só está disponível para uso na origem do app.

O recurso será armazenado como uma resposta opaca, o que significa que seu código não poderá acessar nem modificar o conteúdo ou os cabeçalhos dessa resposta. Além disso, as respostas opacas não expõem o tamanho real na API de armazenamento, o que afeta as cotas. Alguns navegadores expõem tamanhos grandes, como 7 MB, mesmo que o arquivo tenha apenas 1 KB.

Atualizar e excluir recursos

É possível atualizar recursos usando cache.put(request, response) e excluir recursos com delete(request).

Consulte a documentação do objeto de cache para mais detalhes.

Depurar o armazenamento em cache

Muitos navegadores oferecem uma maneira de depurar o conteúdo do armazenamento em cache na guia "Application" das Ferramentas do desenvolvedor. Nela, você pode conferir o conteúdo de cada cache na origem atual. Vamos abordar mais sobre essas ferramentas no capítulo Ferramentas e depuração.

Depuração do Chrome DevTools no conteúdo do armazenamento em cache.

Recursos