Introductie van achtergrond ophalen

In 2015 hebben we Achtergrondsynchronisatie geïntroduceerd , waarmee de servicemedewerker zijn werk kan uitstellen totdat de gebruiker verbinding heeft. Dit betekent dat de gebruiker een bericht kan typen, op verzenden kan drukken en de site kan verlaten in de wetenschap dat het bericht nu zal worden verzonden of wanneer er verbinding is.

Het is een nuttige functie, maar het vereist dat de servicemedewerker in leven blijft tijdens de duur van het ophalen. Dat is geen probleem voor korte stukjes werk, zoals het verzenden van een bericht, maar als de taak te lang duurt, zal de browser de servicemedewerker doden, anders is het een risico voor de privacy en de batterij van de gebruiker.

Dus wat als u iets moet downloaden dat lang kan duren, zoals een film, podcasts of niveaus van een game. Dat is waar Background Fetch voor is.

Background Fetch is standaard beschikbaar sinds Chrome 74.

Hier is een korte demo van twee minuten die de traditionele stand van zaken laat zien, versus het gebruik van Background Fetch:

Probeer de demo zelf en blader door de code .

Hoe het werkt

Een achtergrondophaalactie werkt als volgt:

  1. U vertelt de browser om een ​​groep ophaalacties op de achtergrond uit te voeren.
  2. De browser haalt die dingen op en geeft de voortgang aan de gebruiker weer.
  3. Zodra het ophalen is voltooid of mislukt, opent de browser uw servicemedewerker en activeert een gebeurtenis om u te vertellen wat er is gebeurd. Hier beslist u wat u eventueel met de reacties doet.

Als de gebruiker na stap 1 pagina's op uw site sluit, is dat geen probleem. De download gaat door. Omdat het ophalen goed zichtbaar is en gemakkelijk kan worden afgebroken, is er geen sprake van privacyproblemen door een veel te lange synchronisatietaak op de achtergrond. Omdat de servicemedewerker niet voortdurend aan het werk is, bestaat er geen angst dat hij het systeem zou kunnen misbruiken, zoals het minen van bitcoin op de achtergrond.

Op sommige platforms (zoals Android) is het mogelijk dat de browser na stap 1 sluit, omdat de browser het ophalen aan het besturingssysteem kan overdragen.

Als de gebruiker de download start terwijl hij offline is, of offline gaat tijdens de download, wordt het ophalen op de achtergrond gepauzeerd en later hervat.

De API

Functie detecteren

Zoals bij elke nieuwe functie wilt u detecteren of de browser deze ondersteunt. Voor Background Fetch is het zo simpel als:

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

Een achtergrondophaalactie starten

De hoofd-API blokkeert de registratie van een servicemedewerker , dus zorg ervoor dat je eerst een servicemedewerker hebt geregistreerd. Dan:

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

backgroundFetch.fetch heeft drie argumenten nodig:

Parameters
id string
identificeert op unieke wijze deze achtergrondophaalactie.

backgroundFetch.fetch zal weigeren als de ID overeenkomt met een bestaande achtergrondophaalactie.

requests Array< Request |string>
De dingen die je moet halen. Tekenreeksen worden behandeld als URL's en omgezet in Request via new Request(theString) .

Je kunt dingen van andere oorsprong ophalen, zolang de bronnen dit toestaan ​​via CORS .

Opmerking: Chrome ondersteunt momenteel geen verzoeken waarvoor een CORS-preflight vereist is.

options Een object dat het volgende kan bevatten:
options.title string
Een titel die de browser samen met de voortgang kan weergeven.
options.icons Array< IconDefinition >
Een array van objecten met een `src`, `size` en `type`.
options.downloadTotal number
De totale grootte van de antwoordteksten (nadat ze zijn uitgepakt).

Hoewel dit optioneel is, wordt u ten zeerste aanbevolen dit op te geven. Het wordt gebruikt om de gebruiker te vertellen hoe groot de download is en om voortgangsinformatie te verstrekken. Als u dit niet opgeeft, zal de browser de gebruiker vertellen dat de grootte onbekend is, waardoor de kans groter is dat de gebruiker de download afbreekt.

Als het aantal ophaaldownloads op de achtergrond het hier opgegeven aantal overschrijdt, wordt dit afgebroken. Het is prima als de download kleiner is dan de downloadTotal , dus als je niet zeker weet wat het downloadtotaal zal zijn, kun je het beste voorzichtig zijn.

backgroundFetch.fetch retourneert een belofte die wordt opgelost met een BackgroundFetchRegistration . Ik zal de details daarvan later bespreken. De belofte wordt afgewezen als de gebruiker zich heeft afgemeld voor downloads of als een van de opgegeven parameters ongeldig is.

Door veel verzoeken voor een enkele ophaalactie op de achtergrond aan te bieden, kunt u dingen combineren die logischerwijs één ding zijn voor de gebruiker. Een film kan bijvoorbeeld worden opgesplitst in duizenden bronnen (typisch bij MPEG-DASH ) en worden geleverd met extra bronnen zoals afbeeldingen. Een niveau van een game kan over veel JavaScript-, beeld- en audiobronnen worden verspreid. Maar voor de gebruiker is het gewoon ‘de film’, of ‘het niveau’.

Een bestaande achtergrond ophalen

U kunt als volgt een bestaande achtergrond ophalen:

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

…door de id van de gewenste achtergrondophaalactie door te geven. get rendement undefined als er geen actieve achtergrondophaalactie is met die ID.

Een ophaalactie op de achtergrond wordt als 'actief' beschouwd vanaf het moment dat deze wordt geregistreerd, totdat deze slaagt, mislukt of wordt afgebroken.

Je kunt een lijst krijgen met alle actieve ophaalacties op de achtergrond met behulp van getIds :

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

Ophaalregistraties op de achtergrond

Een BackgroundFetchRegistration ( bgFetch in de bovenstaande voorbeelden) heeft het volgende:

Eigenschappen
id string
De ID van de achtergrondophaalactie.
uploadTotal number
Het aantal bytes dat naar de server moet worden verzonden.
uploaded number
Het aantal bytes dat succesvol is verzonden.
downloadTotal number
De waarde die werd opgegeven toen het ophalen op de achtergrond werd geregistreerd, of nul.
downloaded number
Het aantal succesvol ontvangen bytes.

Deze waarde kan afnemen. Als de verbinding bijvoorbeeld wegvalt en het downloaden niet kan worden hervat, in welk geval de browser het ophalen van die bron helemaal opnieuw start.

result

Een van de volgende:

  • "" - Het ophalen op de achtergrond is actief, dus er is nog geen resultaat.
  • "success" - Het ophalen van de achtergrond is gelukt.
  • "failure" - Het ophalen op de achtergrond is mislukt. Deze waarde verschijnt alleen als het ophalen op de achtergrond volledig mislukt, omdat de browser het niet opnieuw kan proberen/hervatten.
failureReason

Een van de volgende:

  • "" - Het ophalen op de achtergrond is niet mislukt.
  • "aborted" – Het ophalen op de achtergrond is afgebroken door de gebruiker, of abort() is aangeroepen.
  • "bad-status" - Een van de antwoorden had de status 'not-ok', bijvoorbeeld 404.
  • "fetch-error" - Een van de ophaalacties is om een ​​andere reden mislukt, bijvoorbeeld CORS, MIX, een ongeldig gedeeltelijk antwoord of een algemene netwerkfout voor een ophaalactie die niet opnieuw kan worden geprobeerd.
  • "quota-exceeded" : het opslagquotum is bereikt tijdens het ophalen op de achtergrond.
  • "download-total-exceeded" - Het opgegeven `downloadTotal` is overschreden.
recordsAvailable boolean
Zijn de onderliggende verzoeken/antwoorden toegankelijk?

Zodra dit false is, kan match en matchAll niet worden gebruikt.

Methoden
abort() Retourneert Promise<boolean>
Breek het ophalen van de achtergrond af.

De geretourneerde belofte wordt opgelost met true als het ophalen met succes is afgebroken.

matchAll(request, opts) Retourneert Promise<Array<BackgroundFetchRecord>>
Ontvang de verzoeken en antwoorden.

De argumenten hier zijn hetzelfde als die van de cache-API . Bellen zonder argumenten levert een belofte op voor alle records.

Zie hieronder voor meer details.

match(request, opts) Retourneert Promise<BackgroundFetchRecord>
Zoals hierboven, maar opgelost bij de eerste wedstrijd.
Evenementen
progress Wordt geactiveerd wanneer een van uploaded , downloaded , result of failureReason wijzigingen plaatsvindt.

Het bijhouden van de voortgang

Dit kan via het progress . Houd er rekening mee dat downloadTotal de waarde is die u heeft opgegeven, of 0 als u geen waarde heeft opgegeven.

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

Het ontvangen van de verzoeken en antwoorden

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 is een BackgroundFetchRecord en ziet er als volgt uit:

Eigenschappen
request Request
Het verzoek dat is ingediend.
responseReady Promise<Response>
Het opgehaalde antwoord.

Het antwoord zit achter een belofte omdat deze mogelijk nog niet is ontvangen. De belofte wordt afgewezen als het ophalen mislukt.

Evenementen voor servicemedewerkers

Evenementen
backgroundfetchsuccess Alles is succesvol opgehaald.
backgroundfetchfailure Een of meer ophaalbewerkingen zijn mislukt.
backgroundfetchabort Een of meer ophaalbewerkingen zijn mislukt.

Dit is alleen echt handig als u gerelateerde gegevens wilt opschonen.

backgroundfetchclick De gebruiker klikte op de downloadvoortgangsinterface.

De gebeurtenisobjecten hebben het volgende:

Eigenschappen
registration BackgroundFetchRegistration
Methoden
updateUI({ title, icons }) Hiermee kunt u de titel/pictogrammen wijzigen die u aanvankelijk hebt ingesteld. Dit is optioneel, maar hiermee kunt u indien nodig meer context bieden. U kunt dit slechts *eenmaal* doen tijdens de gebeurtenissen backgroundfetchsuccess en backgroundfetchfailure .

Reageren op succes/mislukking

We hebben de progress al gezien, maar dat is alleen nuttig als de gebruiker een pagina op uw site heeft geopend. Het belangrijkste voordeel van ophalen op de achtergrond is dat alles blijft werken nadat de gebruiker de pagina heeft verlaten of zelfs de browser heeft gesloten.

Als het ophalen op de achtergrond succesvol is voltooid, ontvangt uw servicemedewerker de gebeurtenis backgroundfetchsuccess en is event.registration de registratie voor het ophalen op de achtergrond.

Na deze gebeurtenis zijn de opgehaalde verzoeken en antwoorden niet langer toegankelijk, dus als u ze wilt behouden, verplaats ze dan ergens naar de cache-API .

Zoals bij de meeste servicemedewerkergebeurtenissen gebruikt u event.waitUntil zodat de servicemedewerker weet wanneer de gebeurtenis is voltooid.

In uw servicemedewerker bijvoorbeeld:

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

Het mislukken kan te maken hebben met een enkele 404, wat misschien niet belangrijk voor je was, dus het kan toch de moeite waard zijn om enkele reacties naar een cache te kopiëren, zoals hierboven.

Reageren op klik

De gebruikersinterface die de downloadvoortgang en het resultaat weergeeft, is klikbaar. Met de gebeurtenis backgroundfetchclick in de service worker kunt u hierop reageren. Zoals hierboven zal event.registration de ophaalregistratie op de achtergrond zijn.

Het gebruikelijke wat u met deze gebeurtenis kunt doen, is een venster openen:

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

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

Aanvullende bronnen

Correctie: in een eerdere versie van dit artikel werd Background Fetch ten onrechte een "webstandaard" genoemd. De API bevindt zich momenteel niet op het standaardspoor, de specificatie is te vinden in WICG als een concept-communitygroeprapport.