Przedstawiamy pobieranie w tle

Jake Archibald
Jake Archibald

W 2015 r. wprowadziliśmy synchronizację w tle, która umożliwia skrypt service worker w celu odroczenia pracy do momentu uzyskania połączenia przez użytkownika. Oznacza to, że użytkownik może wpisać wiadomość, naciśnij przycisk Wyślij i opuść witrynę, wiedząc, że wiadomość zostanie wysłana teraz lub gdy mają łączność.

Jest to przydatna funkcja, ale wymaga, aby skrypt service worker był aktywny pobrać. Nie stanowi to problemu w przypadku krótkich zadań, takich jak wysyłanie wiadomości, jeśli przeglądarka wyłączy skrypt service worker, ponieważ może to zagrażać prywatności użytkownika baterii.

Co więc w sytuacji, gdy musisz pobrać coś, co zajmuje dużo czasu, np. film, podcast poziomów gry. Właśnie do tego służy pobieranie w tle.

Pobieranie w tle jest dostępne domyślnie od Chrome 74.

Oto krótka, dwuminutowa prezentacja, która pokazuje, jak tradycyjne funkcje działają w odróżnieniu od pobierania w tle:

Wypróbuj wersję demonstracyjną i przejrzyj kod.

Jak to działa

Proces pobierania w tle działa w następujący sposób:

  1. Mówisz przeglądarce, aby wykonywała w tle grupę pobierania.
  2. Przeglądarka pobiera te dane, a następnie wyświetla użytkownikowi postęp.
  3. Gdy pobieranie się zakończy lub się nie uda, przeglądarka otworzy skrypt service worker i uruchomi zdarzenie. i opowie, co się stało. Na tym etapie możesz zdecydować, co zrobić z odpowiedziami.

Jeśli po wykonaniu kroku 1 użytkownik zamknie strony w Twojej witrynie, pobieranie będzie kontynuowane. Ponieważ pobieranie jest bardzo widoczne i można łatwo je przerwać, nie ma obawy o prywatność, synchronizacji w tle. Skrypt service worker nie jest stale uruchomiony, więc nie jest to problem. że może nadużywać systemu, np. wydobywać bitcoiny w tle.

Na niektórych platformach (takich jak Android) przeglądarka może się zamknąć po kroku 1, ponieważ przeglądarka może przekazać pobieranie do systemu operacyjnego.

Jeśli użytkownik rozpocznie pobieranie, będąc offline, lub przejdzie w tryb offline podczas pobierania, działanie w tle pobieranie zostanie wstrzymane i wznowione później.

Interfejs API

Wykrywanie cech

Tak jak w przypadku każdej nowej funkcji, musisz sprawdzić, czy przeglądarka ją obsługuje. W przypadku pobierania w tle tak proste, jak:

if ('BackgroundFetchManager' in self) {
  // This browser supports Background Fetch!
}

Rozpoczynanie pobierania w tle

Główny interfejs API zawiesza się z rejestracją skryptu service worker, dlatego najpierw musisz zarejestrować skrypt service worker. Następnie:

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

Funkcja backgroundFetch.fetch przyjmuje 3 argumenty:

Parametry
id string
jednoznacznie identyfikuje to pobranie w tle.

backgroundFetch.fetch odrzuci, jeśli identyfikator pasuje do istniejącego tła pobrać.

requests Array<Request|string>
Rzeczy do pobrania. Ciągi znaków będą traktowane jako adresy URL i przekształcane w Request za pośrednictwem: new Request(theString).

Możesz pobierać elementy z innych źródeł, o ile pozwalają na to zasoby CORS.

Uwaga: Chrome obecnie nie obsługuje żądań, które: wymagają procesu wstępnego CORS.

options Obiekt, który może zawierać:
options.title string
Tytuł, który wyświetla się w przeglądarce wraz z postępem.
options.icons Array<IconDefinition>
Tablica obiektów z „src”, „size” i „typem”.
options.downloadTotal number
Całkowity rozmiar treści odpowiedzi (po rozpakowaniu gzip).

Chociaż jest to opcjonalne, zdecydowanie zalecamy jego podanie. Pozwala określić, rozmiar pliku do pobrania i informacje o postępach. Jeśli nie podasz przeglądarki poinformuje użytkownika, że rozmiar jest nieznany, i w rezultacie użytkownik może może przerwać pobieranie.

Jeśli pobieranie w tle przekroczy podaną tutaj liczbę, pobieranie zostanie przerwane. Jest Nie ma sprawy, jeśli rozmiar pobieranego pliku jest mniejszy niż downloadTotal. ale lepiej jest zachować ostrożność.

Funkcja backgroundFetch.fetch zwraca obietnicę, która zwraca wartość BackgroundFetchRegistration. tak szczegóły omówimy później. Obietnica zostanie odrzucona, jeśli użytkownik zrezygnował z pobierania plików. podanych parametrów jest nieprawidłowe.

Udostępnianie wielu żądań na jedno pobieranie w tle pozwala łączyć elementy, które są logicznie z perspektywy użytkownika. Na przykład film może zostać podzielony na tysiące zasobów (zwykle przy MPEG-DASH), i dostarczać dodatkowe zasoby, np. obrazy. Poziom gry może być rozłożony na wielu zasobów JavaScript, obrazów i dźwięku. Dla użytkownika to jest tylko „film” lub „poziom”.

Uzyskiwanie istniejącego pobierania w tle

Dotychczasowe pobieranie w tle można pobrać w ten sposób:

navigator.serviceWorker.ready.then(async (swReg) => {
  const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});

...przekazując id żądanego pobierania w tle. get zwraca wartość undefined, jeśli nie ma podanej wartości jest aktywne pobieranie w tle z tym identyfikatorem.

Pobieranie w tle jest uznawane za „aktywne” od momentu jego rejestracji aż do momentu, gdy się powiedzie, nie powiedzie się lub zostanie przerwane.

Listę wszystkich aktywnych pobrań w tle możesz wyświetlić za pomocą parametru getIds:

navigator.serviceWorker.ready.then(async (swReg) => {
  const ids = await swReg.backgroundFetch.getIds();
});

Rejestracje pobierania w tle

Pole BackgroundFetchRegistration (bgFetch w powyższych przykładach) ma następujące właściwości:

Właściwości
id string
Identyfikator pobierania w tle.
uploadTotal number
Liczba bajtów, które mają zostać wysłane do serwera.
uploaded number
Liczba bajtów, które zostały wysłane.
downloadTotal number
Wartość podana podczas rejestrowania pobierania w tle lub zero.
downloaded number
Liczba bajtów, które zostały odebrane.

Ta wartość może się zmniejszyć. Jeśli na przykład połączenie zostanie przerwane i nie będzie można pobrać — w takim przypadku przeglądarka rozpoczyna pobieranie tego zasobu od początku.

result

Jedna z tych wartości:

  • "" – pobieranie w tle jest aktywne, więc nie ma jeszcze wyniku.
  • "success" – udało się pobrać w tle.
  • "failure" – nie udało się pobrać tła. Ta wartość pojawia się tylko wtedy, gdy pobieranie w tle całkowicie kończy się niepowodzeniem, ponieważ przeglądarka nie może ponowić/wznowić jej pobierania.
failureReason

Jedna z tych wartości:

  • "" – nie udało się pobrać w tle.
  • "aborted" – pobieranie w tle zostało przerwane przez użytkownika lub Zadzwoniono na: abort().
  • "bad-status" – jedna z odpowiedzi miała stan „Nieprawidłowo”, np. 404.
  • "fetch-error" – jedno z pobrań nie powiodło się z innego powodu, np. CORS, MIX, nieprawidłowa odpowiedź częściowa lub ogólna awaria sieci podczas pobierania, nie można spróbować ponownie.
  • "quota-exceeded" – osiągnięto limit miejsca na dane w tle pobrać.
  • "download-total-exceeded" – podana wartość „downloadTotal” wynosiła
recordsAvailable boolean
Czy można uzyskać dostęp do powiązanych żądań/odpowiedzi?

Gdy ma wartość Fałsz, nie można używać match ani matchAll.

Metody
abort() Zwraca Promise<boolean>
Przerywanie pobierania w tle.

Zwrócona obietnica kończy się z wartością „true”, jeśli pobieranie zostało przerwane.

matchAll(request, opts) Zwraca Promise<Array<BackgroundFetchRecord>>
Pobierz żądania i udzielania odpowiedzi.

Argumenty podane tutaj są takie same jak pamięć podręczna API. Wywołanie bez argumentów zwraca obietnicę dla wszystkich rekordów.

Więcej informacji znajdziesz poniżej.

match(request, opts) Zwraca wartość Promise<BackgroundFetchRecord>
Tak jak wyżej, ale kończy się wartością w pierwszej kolejności.
Wydarzenia
progress Uruchamiane, gdy dowolna z tych wartości: uploaded, downloaded, result lub failureReason zmiana.

Śledzenie postępów

Możesz to zrobić za pomocą zdarzenia progress. Pamiętaj, że downloadTotal jest wartością bez względu na to, lub 0, jeśli nie podano wartości.

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}%`);
});

Uzyskiwanie żądań i odpowiedzi

bgFetch.match('/ep-5.mp3').then(async (record) => {
  if (!record) {
    console.log('No record found');
    return;
  }

  console.log(`Here's the request`, record.request);
  const response = await record.responseReady;
  console.log(`And here's the response`, response);
});

record to BackgroundFetchRecord i wygląda tak:

Właściwości
request Request
przesłane żądanie,
responseReady Promise<Response>
Pobrana odpowiedź.

Odpowiedź kryje się za obietnicą, ponieważ być może jeszcze jej nie otrzymano. Obietnica zostanie odrzucony, jeśli nie uda się pobrać.

Zdarzenia Service Worker

Wydarzenia
backgroundfetchsuccess Udało się pobrać wszystko.
backgroundfetchfailure Nie udało się pobrać co najmniej jednego pliku.
backgroundfetchabort Nie udało się pobrać co najmniej jednego pliku.

Jest to przydatne tylko wtedy, gdy chcesz usunąć powiązane dane.

backgroundfetchclick Użytkownik kliknął interfejs postępu pobierania.

Obiekty zdarzeń mają następujące elementy:

Właściwości
registration BackgroundFetchRegistration
Metody
updateUI({ title, icons }) Umożliwia zmianę początkowo ustawionych tytułów lub ikon. Jest to opcjonalne, ale pozwala podaj w razie potrzeby więcej kontekstu. Możesz to zrobić tylko *raz* w trakcie Zdarzenia: backgroundfetchsuccess i backgroundfetchfailure.

Reagowanie na sukces/niepowodzenie

Widzimy już zdarzenie progress, ale przydaje się ono tylko wtedy, gdy użytkownik ma otwartą stronę w Twojej witrynie. Główną zaletą pobierania w tle jest to, że wszystko działa, gdy użytkownik opuści a nawet zamyka przeglądarkę.

Jeśli pobieranie w tle się zakończy, skrypt service worker otrzyma zdarzenie backgroundfetchsuccess, a event.registration będzie rejestracją pobierania w tle.

Po tym zdarzeniu pobrane żądania i odpowiedzi przestaną być dostępne, więc jeśli chcesz je zachować, przenieś w podobny sposób do interfejsu API typucache.

Podobnie jak w przypadku większości zdarzeń skryptu service worker, użyj zasady event.waitUntil, aby mechanizm ten wie, kiedy zdarzenie zakończono.

Na przykład w mechanizmie Service Worker:

addEventListener('backgroundfetchsuccess', (event) => {
  const bgFetch = event.registration;

  event.waitUntil(async function() {
    // Create/open a cache.
    const cache = await caches.open('downloads');
    // Get all the records.
    const records = await bgFetch.matchAll();
    // Copy each request/response across.
    const promises = records.map(async (record) => {
      const response = await record.responseReady;
      await cache.put(record.request, response);
    });

    // Wait for the copying to complete.
    await Promise.all(promises);

    // Update the progress notification.
    event.updateUI({ title: 'Episode 5 ready to listen!' });
  }());
});

Błędy mogły sprowadzić się do pojedynczego błędu 404, który może nie być dla Ciebie ważny, nadal warto skopiować niektóre odpowiedzi do pamięci podręcznej w sposób opisany powyżej.

Reakcja na kliknięcie

Interfejs, w którym widać postęp pobierania i wynik, można kliknąć. Wydarzenie backgroundfetchclick w: umożliwia zareagowanie na ten proces. Tak jak powyżej, tłem będzie event.registration pobierz rejestrację.

Zazwyczaj w przypadku tego zdarzenia należy otworzyć okno:

addEventListener('backgroundfetchclick', (event) => {
  const bgFetch = event.registration;

  if (bgFetch.result === 'success') {
    clients.openWindow('/latest-podcasts');
  } else {
    clients.openWindow('/download-progress');
  }
});

Dodatkowe materiały

Poprawka: w poprzedniej wersji tego artykułu pobieranie w tle było błędnie określane jako „standard internetowy”. Interfejs API nie spełnia obecnie standardów. Specyfikację można znaleźć w WICG jako wersję roboczą raportu dotyczącego grupy społeczności.