sincronização-do-segundo plano-da-caixa de trabalho

Quando você envia dados para um servidor da Web, às vezes as solicitações falham. Isso pode ocorrer porque o usuário perdeu a conectividade ou porque o servidor está inativo. Em ambos os casos, tente enviar as solicitações novamente mais tarde.

A nova API BackgroundSync é a solução ideal para esse problema. Quando um service worker detecta que uma solicitação de rede falhou, ele pode se registrar para receber um evento sync, que é entregue quando o navegador acredita que a conectividade retornou. O evento de sincronização pode ser enviado mesmo que o usuário tenha saído do aplicativo, o que o torna muito mais eficaz do que o método tradicional de repetição de solicitações com falha.

A sincronização em segundo plano do Workbox foi criada para facilitar o uso da API BackgroundSync e a integração com outros módulos do Workbox. Ela também implementa uma estratégia substituta para navegadores que ainda não implementam BackgroundSync.

Os navegadores compatíveis com a API BackgroundSync vão reproduzir automaticamente as solicitações com falha em seu nome em um intervalo gerenciado pelo navegador, provavelmente usando espera exponencial entre as tentativas de repetição. Em navegadores que não oferecem suporte nativo à API BackgroundSync, o Workbox Background Sync tentará uma repetição automaticamente sempre que o service worker for iniciado.

Uso básico

A maneira mais fácil de usar a sincronização em segundo plano é usar a Plugin, que automaticamente enfileira as solicitações com falha e as repete quando eventos sync futuros são disparados.

import {BackgroundSyncPlugin} from 'workbox-background-sync';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
  maxRetentionTime: 24 * 60, // Retry for max of 24 Hours (specified in minutes)
});

registerRoute(
  /\/api\/.*\/*.json/,
  new NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
  'POST'
);

BackgroundSyncPlugin hooks no callback do plug-in fetchDidFail, e fetchDidFail só será invocado se houver uma exceção gerada, provavelmente devido a uma falha de rede. Isso significa que as solicitações não serão repetidas se houver uma resposta recebida com um status de erro 4xx ou 5xx. Se você quiser repetir todas as solicitações que resultam em, por exemplo, um status 5xx, adicione um plug-in fetchDidSucceed à sua estratégia:

const statusPlugin = {
  fetchDidSucceed: ({response}) => {
    if (response.status >= 500) {
      // Throwing anything here will trigger fetchDidFail.
      throw new Error('Server error.');
    }
    // If it's not 5xx, use the response as-is.
    return response;
  },
};

// Add statusPlugin to the plugins array in your strategy.

Uso avançado

A sincronização em segundo plano da caixa de trabalho também fornece uma classe Queue, que é possível instanciar e adicionar solicitações com falha. As solicitações com falha são armazenadas no IndexedDB e são repetidas quando o navegador acha que a conectividade foi restaurada (ou seja, quando recebe o evento de sincronização).

Como criar uma fila

Para criar uma fila de sincronização em segundo plano da Workbox, crie-a com um nome de fila, que precisa ser exclusivo para sua origin:

import {Queue} from 'workbox-background-sync';

const queue = new Queue('myQueueName');

O nome da fila é usado como parte do nome da tag que recebe a codificação register() pela SyncManager global. Ele também é usado como o nome do Object Store para o banco de dados IndexedDB.

Como adicionar uma solicitação à fila

Depois de criar sua instância Queue, é possível adicionar solicitações com falha a ela. Adicione uma solicitação com falha invocando o método .pushRequest(). Por exemplo, o código a seguir captura todas as solicitações que falham e as adiciona à fila:

import {Queue} from 'workbox-background-sync';

const queue = new Queue('myQueueName');

self.addEventListener('fetch', event => {
  // Add in your own criteria here to return early if this
  // isn't a request that should use background sync.
  if (event.request.method !== 'POST') {
    return;
  }

  const bgSyncLogic = async () => {
    try {
      const response = await fetch(event.request.clone());
      return response;
    } catch (error) {
      await queue.pushRequest({request: event.request});
      return error;
    }
  };

  event.respondWith(bgSyncLogic());
});

Depois de adicionada à fila, a solicitação é repetida automaticamente quando o service worker recebe o evento sync, que acontece quando o navegador pensa que a conectividade foi restaurada. Os navegadores que não oferecem suporte à API BackgroundSync vão tentar enviar a fila novamente toda vez que o service worker for iniciado. Isso exige que a página que controla o service worker esteja em execução, então não será tão eficaz.

Testar a sincronização em segundo plano da caixa de trabalho

Infelizmente, o teste do BackgroundSync é um pouco pouco intuitivo e difícil por vários motivos.

A melhor abordagem para testar a implementação é fazer o seguinte:

  1. Carregue uma página e registre o service worker.
  2. Desative a rede do computador ou o servidor da Web.
    • NÃO USE O GOOGLE DEVTOOLS OFF-LINE. A caixa de seleção off-line no DevTools só afeta solicitações da página. As solicitações do Service Worker continuarão a ser processadas.
  3. Faça solicitações de rede que precisam ser enfileiradas com a sincronização em segundo plano do Workbox.
    • É possível verificar se as solicitações foram colocadas na fila consultando Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests
  4. Agora, ative a rede ou o servidor da Web.
  5. Para forçar um evento sync antecipado, acesse Chrome DevTools > Application > Service Workers, insira o nome da tag de workbox-background-sync:<your queue name>, em que <your queue name> deve ser o nome da fila definida, e clique no botão "Sincronizar".

    Exemplo do botão &quot;Sincronizar&quot; no Chrome DevTools

  6. Você verá as solicitações de rede serem transmitidas para as solicitações com falha, e os dados do IndexedDB estarão vazios, já que as solicitações foram repetidas com sucesso.

Tipos

BackgroundSyncPlugin

Uma classe que implementa o callback do ciclo de vida fetchDidFail. Isso facilita a adição de solicitações com falha a uma fila de sincronização em segundo plano.

Propriedades

Queue

Uma classe para gerenciar o armazenamento de solicitações com falha no IndexedDB e tentar novamente mais tarde. Todas as partes do processo de armazenamento e repetição podem ser observadas com callbacks.

Propriedades

  • construtor

    void

    Cria uma instância de Queue com as opções fornecidas

    A função constructor tem esta aparência:

    (name: string,options?: QueueOptions)=> {...}

    • name

      string

      O nome exclusivo dessa fila. Esse nome precisa ser exclusivo porque é usado para registrar eventos de sincronização e armazenar solicitações no IndexedDB específicas para essa instância. Um erro será gerado se um nome duplicado for detectado.

    • opções

      QueueOptions opcional

  • name

    string

  • getAll

    void

    Retorna todas as entradas que não expiraram (por maxRetentionTime). Todas as entradas expiradas são removidas da fila.

    A função getAll tem esta aparência:

    ()=> {...}

    • retorna

      Promise<QueueEntry[]>

  • popRequest

    void

    Remove e retorna a última solicitação na fila, com o carimbo de data/hora e todos os metadados. O objeto retornado tem a forma: {request, timestamp, metadata}.

    A função popRequest tem esta aparência:

    ()=> {...}

    • retorna

      Promise<QueueEntry>

  • pushRequest

    void

    Armazena a solicitação passada no IndexedDB (com o carimbo de data/hora e quaisquer metadados) no final da fila.

    A função pushRequest tem esta aparência:

    (entry: QueueEntry)=> {...}

    • entry

      QueueEntry

    • retorna

      Promise<void>

  • registerSync

    void

    Registra um evento de sincronização com uma tag exclusiva para esta instância.

    A função registerSync tem esta aparência:

    ()=> {...}

    • retorna

      Promise<void>

  • replayRequests

    void

    Percorra cada solicitação na fila e tenta buscá-la novamente. Se uma solicitação não for buscada novamente, ela será colocada de volta na mesma posição na fila, que registra uma nova tentativa para o próximo evento de sincronização.

    A função replayRequests tem esta aparência:

    ()=> {...}

    • retorna

      Promise<void>

  • shiftRequest

    void

    Remove e retorna a primeira solicitação na fila, com o carimbo de data/hora e todos os metadados. O objeto retornado tem a forma: {request, timestamp, metadata}.

    A função shiftRequest tem esta aparência:

    ()=> {...}

    • retorna

      Promise<QueueEntry>

  • tamanho

    void

    Retorna o número de entradas presentes na fila. As entradas expiradas (por maxRetentionTime) também são incluídas nessa contagem.

    A função size tem esta aparência:

    ()=> {...}

    • retorna

      Prometer<número>

  • unshiftRequest

    void

    Armazena a solicitação transmitida no IndexedDB (com o carimbo de data/hora e quaisquer metadados) no início da fila.

    A função unshiftRequest tem esta aparência:

    (entry: QueueEntry)=> {...}

    • entry

      QueueEntry

    • retorna

      Promise<void>

QueueOptions

Propriedades

  • forceSyncFallback

    booleano opcional

  • maxRetentionTime

    número opcional

  • onSync

    OnSyncCallback opcional

QueueStore

Uma classe para gerenciar solicitações de armazenamento de uma fila no IndexedDB, indexadas pelo nome da fila para facilitar o acesso.

A maioria dos desenvolvedores não precisa acessar essa classe diretamente. Ela fica exposta para casos de uso avançados.

Propriedades

  • construtor

    void

    Associa essa instância a uma instância Queue. Assim, as entradas adicionadas podem ser identificadas pelo nome da fila.

    A função constructor tem esta aparência:

    (queueName: string)=> {...}

    • queueName

      string

  • deleteEntry

    void

    Exclui a entrada do ID fornecido.

    AVISO: esse método não garante que a entrada excluída pertença a essa fila (ou seja, corresponde a queueName). Mas essa limitação é aceitável porque essa classe não está exposta publicamente. Uma verificação extra tornaria esse método mais lento do que deveria.

    A função deleteEntry tem esta aparência:

    (id: number)=> {...}

    • id

      number

    • retorna

      Promise<void>

  • getAll

    void

    Retorna todas as entradas na loja que correspondem a queueName.

    A função getAll tem esta aparência:

    ()=> {...}

    • retorna

      Promise<QueueStoreEntry[]>

  • popEntry

    void

    Remove e retorna a última entrada na fila que corresponde ao queueName.

    A função popEntry tem esta aparência:

    ()=> {...}

    • retorna

      Promise<QueueStoreEntry>

  • pushEntry

    void

    Anexar uma entrada por último na fila.

    A função pushEntry tem esta aparência:

    (entry: UnidentifiedQueueStoreEntry)=> {...}

    • entry

      UnidentifiedQueueStoreEntry

    • retorna

      Promise<void>

  • shiftEntry

    void

    Remove e retorna a primeira entrada na fila que corresponde ao queueName.

    A função shiftEntry tem esta aparência:

    ()=> {...}

    • retorna

      Promise<QueueStoreEntry>

  • tamanho

    void

    Retorna o número de entradas na loja que correspondem a queueName.

    A função size tem esta aparência:

    ()=> {...}

    • retorna

      Prometer<número>

  • unshiftEntry

    void

    Incluir uma entrada no início da fila.

    A função unshiftEntry tem esta aparência:

    (entry: UnidentifiedQueueStoreEntry)=> {...}

    • entry

      UnidentifiedQueueStoreEntry

    • retorna

      Promise<void>

StorableRequest

Uma classe para facilitar a serialização e desserialização de solicitações para que elas possam ser armazenadas no IndexedDB.

A maioria dos desenvolvedores não precisa acessar essa classe diretamente. Ela fica exposta para casos de uso avançados.

Propriedades

  • construtor

    void

    Aceita um objeto de dados de solicitação que pode ser usado para construir um Request, mas que também pode ser armazenado no IndexedDB.

    A função constructor tem esta aparência:

    (requestData: RequestData)=> {...}

    • requestData

      RequestData

      Um objeto de dados de solicitação que inclui url e todas as propriedades relevantes de [requestInit]https://fetch.spec.whatwg.org/#requestinit.

  • clone

    void

    Cria e retorna um clone profundo da instância.

    A função clone tem esta aparência:

    ()=> {...}

  • toObject

    void

    Retorna um clone profundo do objeto _requestData das instâncias.

    A função toObject tem esta aparência:

    ()=> {...}

    • retorna

      RequestData

  • toRequest

    void

    Converte esta instância em uma solicitação.

    A função toRequest tem esta aparência:

    ()=> {...}

    • retorna

      Solicitação

  • fromRequest

    void

    Converte um objeto de solicitação em um objeto simples que pode ser estruturado clonado ou strings em JSON.

    A função fromRequest tem esta aparência:

    (request: Request)=> {...}

    • request

      Solicitação