skrzynka robocza-synchronizacja-w tle

Gdy wysyłasz dane na serwer WWW, czasami nie można zrealizować żądania. Przyczyną może być utrata połączenia przez użytkownika lub wyłączenie serwera. W każdym z tych przypadków możesz próbować ponownie wysłać żądania później.

Nowy interfejs BackgroundSync API stanowi idealne rozwiązanie tego problemu. Gdy skrypt service worker wykryje, że żądanie sieciowe nie zostało zrealizowane, może zarejestrować się w celu otrzymania zdarzenia sync, które jest wysyłane, gdy przeglądarka uzna, że połączenie zostało przywrócone. Pamiętaj, że zdarzenie synchronizacji może zostać dostarczone, nawet jeśli użytkownik opuści aplikację, dzięki czemu jest to znacznie skuteczniejsze niż tradycyjna metoda ponawiania nieudanych żądań.

Funkcja synchronizacji w tle ułatwia korzystanie z interfejsu BackgroundSync API oraz integrowanie jego wykorzystania z innymi modułami Workbox. Wdraża również strategię zastępczą dla przeglądarek, które nie korzystają jeszcze z funkcji BackgroundSync.

Przeglądarki, które obsługują interfejs BackgroundSync API, będą automatycznie odtwarzać w Twoim imieniu nieudane żądania w interwałie zarządzanym przez przeglądarkę, prawdopodobnie korzystając z wykładniczego ponowienia między kolejnymi próbami. W przeglądarkach, które natywnie nie obsługują interfejsu BackgroundSync API, synchronizacja w tle przez Workbox będzie automatycznie próbować ponownie odtworzyć po każdym uruchomieniu skryptu service worker.

Podstawowe użycie

Najprostszym sposobem korzystania z synchronizacji w tle jest użycie interfejsu Plugin, który automatycznie dodaje nieudane żądania do kolejki i ponawia je po uruchomieniu przyszłych zdarzeń sync.

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 łączy się z wywołaniem zwrotnym wtyczki fetchDidFail, a interfejs fetchDidFail jest wywoływany tylko w przypadku zgłoszenia wyjątku, najprawdopodobniej w wyniku awarii sieci. Oznacza to, że żądania nie będą ponawiane, jeśli otrzymana odpowiedź ma stan błędu 4xx lub 5xx. Jeśli chcesz ponawiać wszystkie żądania, które skutkują np. stanem 5xx, możesz dodać do strategii wtyczkę fetchDidSucceed:

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.

Zaawansowane użycie

Synchronizacja w tle Workbox udostępnia również klasę Queue, do której możesz uruchamiać i dodawać nieudane żądania. Żądania zakończone niepowodzeniem są przechowywane w IndexedDB i ponawiane, gdy przeglądarka uzna, że łączność została przywrócona (czyli otrzyma zdarzenie synchronizacji).

Tworzenie kolejki

Aby utworzyć kolejkę synchronizacji w tle w Workbox, musisz ją utworzyć z nazwą kolejki (musi być unikalna dla Twojej źródła):

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

const queue = new Queue('myQueueName');

Nazwa kolejki jest częścią nazwy tagu, którą tag register() jest szyfrowany przez globalny SyncManager. Jest też używana jako nazwa magazynu obiektów bazy danych IndexedDB.

Dodawanie żądania do kolejki

Po utworzeniu instancji kolejki możesz dodawać do niej nieudane żądania. Nieudane żądanie dodajesz przez wywołanie metody .pushRequest(). Na przykład ten kod wykrywa wszystkie żądania, które się nie powiodły, i dodaje je do kolejki:

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());
});

Po dodaniu do kolejki żądanie jest automatycznie ponawiane, gdy skrypt service worker otrzyma zdarzenie sync (co ma miejsce, gdy przeglądarka uzna, że łączność została przywrócona). Przeglądarki, które nie obsługują interfejsu BackgroundSync API, będą ponawiać próbę uruchomienia kolejki za każdym razem, gdy mechanizm Service Worker zostanie uruchomiony. Wymaga to uruchomienia strony sterującej skryptem service worker, więc nie będzie ono tak skuteczne.

Testowanie synchronizacji w tle

Niestety testowanie BackgroundSync jest w pewnym stopniu nieintuicyjne i trudne z wielu powodów.

Aby przetestować implementację, najlepiej wykonaj te czynności:

  1. Wczytaj stronę i zarejestruj skrypt service worker.
  2. Wyłącz sieć na komputerze lub wyłącz serwer WWW.
    • NIE UŻYWAJ DEVTOOLÓW Chrome OFFLINE. Pole wyboru offline w Narzędziach deweloperskich ma wpływ tylko na żądania ze strony. Żądania skryptu Service Worker będą nadal realizowane.
  3. Twórz żądania sieciowe, które powinny zostać umieszczone w kolejce w ramach synchronizacji w tle z Workbox.
    • Aby sprawdzić, czy żądania zostały dodane do kolejki, zajrzyj do narzędzia Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests.
  4. Teraz włącz sieć lub serwer WWW.
  5. Wymuś wcześniejsze zdarzenie sync. Aby to zrobić, wejdź na Chrome DevTools > Application > Service Workers, wpisz nazwę tagu workbox-background-sync:<your queue name>, gdzie <your queue name> powinien być nazwą ustawionej kolejki, a następnie kliknij przycisk „Synchronizuj”.

    Przykład przycisku synchronizacji w Narzędziach deweloperskich w Chrome

  6. Żądania sieciowe powinny być realizowane w przypadku nieudanych żądań, a dane IndexedDB powinny być teraz puste, ponieważ żądania zostały ponownie odtworzone.

Typy

BackgroundSyncPlugin

Klasa implementująca wywołanie zwrotne cyklu życia fetchDidFail. Ułatwia to dodawanie nieudanych żądań do kolejki synchronizacji w tle.

Właściwości

Queue

Klasa do zarządzania przechowywaniem nieudanych żądań w IndexedDB i ponawianiu ich później. Wywołania zwrotne pozwalają obserwować wszystkie etapy procesu przechowywania i odtwarzania.

Właściwości

  • konstruktor

    void

    Tworzy instancję kolejki z podanymi opcjami

    Funkcja constructor wygląda tak:

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

    • nazwa

      string,

      Unikalna nazwa tej kolejki. Ta nazwa musi być unikalna, ponieważ jest używana do rejestrowania zdarzeń synchronizacji i przechowywania żądań w IndexedDB specyficznych dla tej instancji. W przypadku wykrycia zduplikowanej nazwy wyświetli się błąd.

    • Opcje

      Opcjonalne QueueOptions

  • nazwa

    string,

  • getAll

    void

    Zwraca wszystkie wpisy, które nie wygasły (na maxRetentionTime). Wszystkie nieaktualne wpisy są usuwane z kolejki.

    Funkcja getAll wygląda tak:

    ()=> {...}

    • returns

      Promise<QueueEntry[]>

  • popRequest

    void

    Usuwa i zwraca ostatnie żądanie w kolejce (wraz z jego sygnaturą czasową i metadanymi). Zwrócony obiekt ma postać: {request, timestamp, metadata}.

    Funkcja popRequest wygląda tak:

    ()=> {...}

    • returns

      Promise<QueueEntry>

  • pushRequest

    void

    Zapisuje przekazane żądanie w IndexedDB (z jego sygnaturą czasową i metadanymi) na końcu kolejki.

    Funkcja pushRequest wygląda tak:

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

    • wpis

      QueueEntry

    • returns

      Promise<void>

  • registerSync

    void

    Rejestruje zdarzenie synchronizacji z tagiem unikalnym dla tej instancji.

    Funkcja registerSync wygląda tak:

    ()=> {...}

    • returns

      Promise<void>

  • replayRequests

    void

    Przewija każde żądanie w kolejce i próbuje je ponownie pobrać. Jeśli jakiekolwiek żądanie nie zostanie pobrane ponownie, zostanie umieszczone na tym samym miejscu w kolejce (co spowoduje zarejestrowanie ponownej próby dla następnego zdarzenia synchronizacji).

    Funkcja replayRequests wygląda tak:

    ()=> {...}

    • returns

      Promise<void>

  • shiftRequest

    void

    Usuwa i zwraca pierwsze żądanie w kolejce (wraz z jego sygnaturą czasową i metadanymi). Zwrócony obiekt ma postać: {request, timestamp, metadata}.

    Funkcja shiftRequest wygląda tak:

    ()=> {...}

    • returns

      Promise<QueueEntry>

  • rozmiar

    void

    Zwraca liczbę pozycji w kolejce. Pamiętaj, że ta liczba uwzględnia też nieaktualne wpisy (na maxRetentionTime).

    Funkcja size wygląda tak:

    ()=> {...}

    • returns

      Obietnica<number>

  • unshiftRequest

    void

    Zapisuje przekazane żądanie w IndexedDB (z jego sygnaturą czasową i metadanymi) na początku kolejki.

    Funkcja unshiftRequest wygląda tak:

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

    • wpis

      QueueEntry

    • returns

      Promise<void>

QueueOptions

Właściwości

  • forceSyncFallback

    wartość logiczna opcjonalna

  • maxRetentionTime

    Liczba opcjonalnie

  • onSync

    OnSyncCallback opcjonalnie

QueueStore

Klasa do zarządzania przechowywaniem żądań z kolejki w IndexedDB, indeksowana według nazwy kolejki w celu ułatwienia dostępu.

Większość programistów nie musi mieć bezpośredniego dostępu do tych zajęć. Są one dostępne w zaawansowanych przypadkach użycia.

Właściwości

  • konstruktor

    void

    Wiąże tę instancję z instancją kolejki, dzięki czemu dodane wpisy można zidentyfikować na podstawie nazwy kolejki.

    Funkcja constructor wygląda tak:

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

    • queueName

      string,

  • deleteEntry

    void

    Usuwa wpis z podanym identyfikatorem.

    OSTRZEŻENIE: ta metoda nie gwarantuje, że usunięty wpis będzie należeć do tej kolejki (tzn. będzie pasować do queueName). To ograniczenie jest jednak akceptowalne, ponieważ ta klasa nie jest dostępna publicznie. Dodatkowa weryfikacja spowolniłaby działanie tej metody.

    Funkcja deleteEntry wygląda tak:

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

    • id

      Liczba

    • returns

      Promise<void>

  • getAll

    void

    Zwraca wszystkie wpisy w sklepie pasujące do wartości queueName.

    Funkcja getAll wygląda tak:

    ()=> {...}

    • returns

      Promise<QueueStoreEntry[]>

  • popEntry

    void

    Usuwa i zwraca ostatni wpis w kolejce zgodny z queueName.

    Funkcja popEntry wygląda tak:

    ()=> {...}

    • returns

      Promise<QueueStoreEntry>

  • pushEntry

    void

    Dołącz wpis jako ostatni w kolejce.

    Funkcja pushEntry wygląda tak:

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

    • wpis

      UnidentifiedQueueStoreEntry

    • returns

      Promise<void>

  • shiftEntry

    void

    Usuwa i zwraca pierwszy wpis w kolejce zgodny z queueName.

    Funkcja shiftEntry wygląda tak:

    ()=> {...}

    • returns

      Promise<QueueStoreEntry>

  • rozmiar

    void

    Zwraca liczbę wpisów w sklepie pasujących do queueName.

    Funkcja size wygląda tak:

    ()=> {...}

    • returns

      Obietnica<number>

  • unshiftEntry

    void

    Dołącz wpis jako pierwszy na początku kolejki.

    Funkcja unshiftEntry wygląda tak:

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

    • wpis

      UnidentifiedQueueStoreEntry

    • returns

      Promise<void>

StorableRequest

Klasa ułatwiająca serializację i deserializację żądań, co umożliwia ich przechowywanie w IndexedDB.

Większość programistów nie musi mieć bezpośredniego dostępu do tych zajęć. Są one dostępne w zaawansowanych przypadkach użycia.

Właściwości

  • konstruktor

    void

    Akceptuje obiekt danych żądania, którego można użyć do utworzenia Request, ale można go też przechowywać w IndexedDB.

    Funkcja constructor wygląda tak:

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

    • requestData

      RequestData

      Obiekt danych żądania zawierający właściwość url oraz wszystkie istotne właściwości właściwości [requestInit]https://fetch.spec.whatwg.org/#requestinit.

  • klon,

    void

    Tworzy i zwraca głęboką kopię instancji.

    Funkcja clone wygląda tak:

    ()=> {...}

  • toObject

    void

    Zwraca głęboką kopię obiektu instancji _requestData.

    Funkcja toObject wygląda tak:

    ()=> {...}

    • returns

      RequestData

  • toRequest

    void

    Konwertuje tę instancję na żądanie.

    Funkcja toRequest wygląda tak:

    ()=> {...}

    • returns

      Prośba

  • fromRequest

    void

    Konwertuje obiekt Request na zwykły obiekt, który można sklonować lub zakodować w postaci ciągu znaków w formacie JSON.

    Funkcja fromRequest wygląda tak:

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

    • Poproś

      Prośba