Dwukierunkowa komunikacja z skryptami service worker

Andrew Guan
Andrew Guan

W niektórych przypadkach aplikacja internetowa może wymagać ustanowienia dwukierunkowego kanału komunikacji między i skrypt service worker.

Na przykład: w PWA podcastu można utworzyć funkcję umożliwiającą użytkownikowi pobieranie odcinków do konsumpcji offline i zezwalają na skrypt service worker, aby regularnie informować stronę o postępach, dlatego główny thread może aktualizować interfejs użytkownika.

W tym przewodniku omówimy różne sposoby wdrażania dwukierunkowej komunikacji między okno i usługa. instancji roboczej, analizując z różnych interfejsów API, biblioteki Workspace oraz w bardziej zaawansowanych przypadkach.

Schemat przedstawiający skrypt service worker i stronę wymieniającą wiadomości.

Korzystanie z Workbox

workbox-window to zestaw z modułów biblioteki Workspace, które są przeznaczone uruchamianie w kontekście okna. Workbox klasa udostępnia metodę messageSW() służącą do wysyłania wiadomości do zarejestrowanego skryptu service worker instancji oraz oczekują na odpowiedź.

Poniższy kod strony tworzy nową instancję Workbox i wysyła wiadomość do skryptu service worker aby uzyskać jego wersję:

const wb = new Workbox('/sw.js');
wb.register();

const swVersion = await wb.messageSW({type: 'GET_VERSION'});
console.log('Service Worker version:', swVersion);

Skrypt service worker implementuje odbiornik wiadomości i odpowiada skrypt service worker:

const SW_VERSION = '1.0.0';

self.addEventListener('message', (event) => {
  if (event.data.type === 'GET_VERSION') {
    event.ports[0].postMessage(SW_VERSION);
  }
});

Zasadniczo biblioteka wykorzystuje interfejs API przeglądarki, który omówimy w następnej sekcji: Wiadomość kanału, ale wiele z nich szczegóły wdrożenia, które ułatwiają obsługę przy jednoczesnym wykorzystaniu szerokiej przeglądarki obsługiwane przez ten interfejs API.

Diagram przedstawiający dwukierunkową komunikację między stroną a skryptem service worker z użyciem okna Workbox.

Korzystanie z interfejsów API przeglądarki

Jeśli biblioteka Workbox nie spełnia Twoich potrzeb, dostępnych jest kilka interfejsów API niższego poziomu, zaimplementować „dwukierunkową” komunikację między stronami a mechanizmami Service Worker. mają pewne podobieństwa. i różnic:

Podobieństwa:

  • We wszystkich przypadkach komunikacja rozpoczyna się po jednej stronie przez interfejs postMessage() i jest odebrana. z drugiej strony, implementując moduł obsługi message.
  • W praktyce wszystkie dostępne interfejsy API pozwalają nam wdrożyć te same przypadki użycia, ale niektóre z nich może w niektórych sytuacjach uprościć programowanie.

Różnice:

  • Drugą stroną komunikacji są różne sposoby: niektóre wykorzystują bezpośrednie odniesienie do drugiego kontekstu, podczas gdy inni mogą komunikować się pośrednio przez serwer proxy po każdej stronie.
  • Różne przeglądarki obsługują różne przeglądarki.
Diagram przedstawiający dwukierunkową komunikację między stroną a mechanizmem Service Worker oraz dostępnymi interfejsami API przeglądarki.

Interfejs Broadcast Channel API

Obsługa przeglądarek

  • Chrome: 54.
  • Krawędź: 79.
  • Firefox: 38.
  • Safari: 15.4

Źródło

Broadcast Channel API umożliwia podstawową komunikację między kontekstami przeglądania za pomocą BroadcastChannel .

Aby można było go zaimplementować, każdy kontekst musi utworzyć wystąpienie obiektu BroadcastChannel o tym samym identyfikatorze oraz wysyłać i odbierać wiadomości za jej pomocą:

const broadcast = new BroadcastChannel('channel-123');

Obiekt BroadcastChannel udostępnia interfejs postMessage() umożliwiający wysłanie wiadomości do każdego nasłuchującego. kontekst:

//send message
broadcast.postMessage({ type: 'MSG_ID', });

Dowolny kontekst przeglądarki może nasłuchiwać wiadomości za pomocą metody onmessage interfejsu BroadcastChannel obiekt:

//listen to messages
broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'MSG_ID') {
    //process message...
  }
};

Nie ma tu wyraźnego odniesienia do konkretnego kontekstu, więc nie ma potrzeby do skryptu service worker lub konkretnego klienta.

Diagram przedstawiający dwukierunkową komunikację między stroną a skryptem Service Worker z użyciem obiektu kanału transmisji.

Wadą jest to, że na moment pisania tego artykułu interfejs API obsługuje przeglądarki Chrome, Firefox. i Edge, ale inne przeglądarki, takie jak Safari, nie obsługują tej funkcji. jeszcze.

Interfejs API klienta

Obsługa przeglądarek

  • Chrome: 40
  • Edge: 17.
  • Firefox: 44.
  • Safari: 11.1

Źródło

Interfejs API klienta umożliwia uzyskanie odwołanie do wszystkich obiektów WindowClient reprezentujących aktywne karty, które kontroluje skrypt service worker.

Stroną steruje jeden skrypt service worker, nasłuchuje i wysyła wiadomości do aktywny skrypt service worker bezpośrednio przez interfejs serviceWorker:

//send message
navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
});

//listen to messages
navigator.serviceWorker.onmessage = (event) => {
  if (event.data && event.data.type === 'MSG_ID') {
    //process response
  }
};

Podobnie skrypt service worker nasłuchuje wiadomości, implementując odbiornik onmessage:

//listen to messages
self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'MSG_ID') {
    //Process message
  }
});

Aby komunikować się z dowolnym klientem, mechanizm Service Worker uzyskuje tablicę WindowClient obiektów po wykonaniu metod, takich jak Clients.matchAll() i Clients.get(). Dzięki temu może postMessage() dowolne z nich:

//Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
  if (clients && clients.length) {
    //Respond to last focused tab
    clients[0].postMessage({type: 'MSG_ID'});
  }
});
Diagram przedstawiający skrypt service worker komunikujący się z wieloma klientami.

Client API to dobra opcja do łatwej komunikacji ze wszystkimi aktywnymi kartami skryptu service worker w stosunkowo prosty sposób. Ten interfejs API jest obsługiwany przez wszystkie główne przeglądarki, ale nie wszystkie jej metody mogą być dostępne. Sprawdź więc, jak zaimplementować go w witrynie.

Kanał wiadomości

Obsługa przeglądarek

  • Chrome: 2.
  • Krawędź: 12.
  • Firefox: 41.
  • Safari: 5.

Źródło

Wymagania Kanału wiadomości definiowanie i przekazywanie portów z jednego kontekstu do drugiego w celu utworzenia dwukierunkowej komunikacji. kanał.

Aby zainicjować kanał, strona tworzy instancję obiektu MessageChannel i używa go aby wysłać port do zarejestrowanego mechanizmu Service Worker. Strona implementuje również detektor onmessage w aby otrzymywać wiadomości z drugiego kontekstu:

const messageChannel = new MessageChannel();

//Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

//Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};
Diagram przedstawiający stronę przekazującą port do skryptu service worker w celu nawiązania komunikacji dwukierunkowej.

Skrypt service worker odbiera port, zapisuje do niego odwołanie i używa go do wysłania wiadomości do drugiego strona:

let communicationPort;

//Save reference to port
self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

//Send messages
communicationPort.postMessage({type: 'MSG_ID'});

Usługa MessageChannel jest obecnie obsługiwana przez wszystkie główne przeglądarki.

Zaawansowane interfejsy API: synchronizacja w tle i pobieranie w tle

W tym przewodniku przedstawiliśmy sposoby wdrażania technik dwukierunkowej komunikacji przez w prostych przypadkach, np. przez przekazanie komunikatu tekstowego opisującego operację do wykonania lub listy adresów URL. z jednego kontekstu do drugiego. W tej sekcji przyjrzymy się 2 interfejsom API do obsługi – brak połączenia z internetem i długie pobieranie.

Synchronizacja w tle

Obsługa przeglądarek

  • Chrome: 49.
  • Krawędź: 79.
  • Firefox: funkcja nieobsługiwana.
  • Safari: nieobsługiwane.

Źródło

Aplikacja do obsługi czatu może chcieć mieć pewność, że wiadomości nigdy nie zostaną utracone z powodu słabego połączenia. Interfejs Background Sync API umożliwia odkładać ponowienie działań, gdy użytkownik ma stabilne połączenie z internetem; Pozwala to zapewnić, to co użytkownik chce wysłać, jest w rzeczywistości wysyłane.

Zamiast interfejsu postMessage() strona rejestruje sync:

navigator.serviceWorker.ready.then(function (swRegistration) {
  return swRegistration.sync.register('myFirstSync');
});

Skrypt service worker następnie nasłuchuje zdarzenia sync, aby przetworzyć wiadomość:

self.addEventListener('sync', function (event) {
  if (event.tag == 'myFirstSync') {
    event.waitUntil(doSomeStuff());
  }
});

Funkcja doSomeStuff() powinna zwracać obietnicę powodzenia lub niepowodzenia dowolnej wartości co stara się zrobić. Jeśli tak, synchronizacja się zakończy. Jeśli się to nie uda, zostanie zaplanowana kolejna synchronizacja spróbuj jeszcze raz. Synchronizacje ponawiania próby także oczekują na połączenie i wykorzystują rosnący czas ponowienia.

Po wykonaniu operacji skrypt service worker może następnie komunikować się ze stroną w celu zaktualizować interfejs przy użyciu dowolnego z interfejsów API do komunikacji opisanych wcześniej.

Wyszukiwarka Google korzysta z synchronizacji w tle, aby utrwalać nieudane zapytania z powodu słabego połączenia. Następnie spróbuj ponownie je później, gdy użytkownik będzie online. Po wykonaniu operacji przekazują informacje o wynikach użytkownika w powiadomieniu push w przeglądarce:

Diagram przedstawiający stronę przekazującą port do skryptu service worker w celu nawiązania komunikacji dwukierunkowej.

Pobieranie w tle

Obsługa przeglądarek

  • Chrome: 74.
  • Krawędź: 79.
  • Firefox: funkcja nieobsługiwana.
  • Safari: nieobsługiwane.

Źródło

W przypadku stosunkowo krótkich zadań, takich jak wysyłanie wiadomości czy lista adresów URL do przechowywania w pamięci podręcznej, opcje które do tej pory były dobrym wyborem. Jeśli zadanie trwa zbyt długo, przeglądarka wyłączy usługę w innym narzędziu, co zagraża prywatności i baterii użytkownika.

Background Fetch API pozwala na sprawne wykonywanie długich zadań (takich jak pobieranie filmów, podcastów lub poziomów) w usługach service worker danej gry.

Aby komunikować się z skrypcją service worker z poziomu strony, używaj backgroundFetch.fetch zamiast postMessage():

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.fetch(
    'my-fetch',
    ['/ep-5.mp3', 'ep-5-artwork.jpg'],
    {
      title: 'Episode 5: Interesting things.',
      icons: [
        {
          sizes: '300x300',
          src: '/ep-5-icon.png',
          type: 'image/png',
        },
      ],
      downloadTotal: 60 * 1024 * 1024,
    },
  );
});

Obiekt BackgroundFetchRegistration umożliwia stronie nasłuchiwanie zdarzenia progress, które następuje postęp pobierania:

bgFetch.addEventListener('progress', () => {
  // If we didn't provide a total, we can't provide a %.
  if (!bgFetch.downloadTotal) return;

  const percent = Math.round(
    (bgFetch.downloaded / bgFetch.downloadTotal) * 100,
  );
  console.log(`Download progress: ${percent}%`);
});
Diagram przedstawiający stronę przekazującą port do skryptu service worker w celu nawiązania komunikacji dwukierunkowej.
Interfejs jest aktualizowany, aby pokazywać postęp pobierania (po lewej). Dzięki mechanizmom Service Worker operacja może być kontynuowana, gdy wszystkie karty zostaną zamknięte (po prawej).
.

Dalsze kroki

W tym przewodniku przyjrzeliśmy się najbardziej ogólnym przypadkom komunikacji między skryptami strony a skryptami service worker (komunikacja dwukierunkowa).

Często do komunikowania się z drugim potrzebnym jest tylko jeden kontekst, . W poniższych przewodnikach znajdziesz wskazówki, jak wdrożyć techniki jednokierunkowe w Fragmenty stron z i do skryptu service worker wraz z przykładami użycia i przykładami produkcyjnymi:

  • Przewodnik po imperatywnym buforowaniu: wywoływanie skryptu service worker ze strony do z wyprzedzeniem buforować zasoby (np. w scenariuszach wstępnego wczytywania).
  • Aktualizacje komunikatów: wywołuje stronę z poziomu skryptu service worker w celu przekazania informacji o ważnych aktualizacjach (np. o nowej wersji aplikacji internetowej).