2015 haben wir die Hintergrundsynchronisierung eingeführt, mit der der Dienst-Worker Aufgaben verschieben kann, bis der Nutzer eine Internetverbindung hat. Das bedeutet, dass der Nutzer eine Nachricht eingeben, auf „Senden“ klicken und die Website verlassen kann, in dem Wissen, dass die Nachricht entweder sofort oder sobald er eine Verbindung hat, gesendet wird.
Das ist eine nützliche Funktion, erfordert aber, dass der Dienst-Worker während der gesamten Abrufzeit aktiv ist. Das ist bei kurzen Aufgaben wie dem Senden einer Nachricht kein Problem. Wenn die Aufgabe jedoch zu lange dauert, beendet der Browser den Dienst-Worker, da dies sonst ein Risiko für den Datenschutz und die Akkulaufzeit des Nutzers darstellt.
Was ist, wenn Sie etwas herunterladen möchten, was viel Zeit in Anspruch nimmt, z. B. einen Film, Podcasts oder Level eines Spiels? Dafür gibt es den Hintergrundabruf.
Hintergrundabruf ist seit Chrome 74 standardmäßig verfügbar.
In dieser zweiminütigen Demo wird der herkömmliche Zustand im Vergleich zur Verwendung von Hintergrundabruf veranschaulicht:
Probieren Sie die Demo selbst aus und sehen Sie sich den Code an.
Funktionsweise
So funktioniert ein Hintergrundabruf:
- Sie weisen den Browser an, eine Gruppe von Abrufen im Hintergrund auszuführen.
- Der Browser ruft diese Elemente ab und zeigt dem Nutzer den Fortschritt an.
- Sobald der Abruf abgeschlossen oder fehlgeschlagen ist, öffnet der Browser Ihren Service Worker und löst ein Ereignis aus, um Sie über das Ergebnis zu informieren. Hier können Sie festlegen, was mit den Antworten geschehen soll.
Wenn der Nutzer nach Schritt 1 Seiten Ihrer Website schließt, ist das in Ordnung. Der Download wird fortgesetzt. Da der Abruf gut sichtbar ist und leicht abgebrochen werden kann, besteht keine Datenschutzbedenken aufgrund einer viel zu langen Hintergrundsynchronisierungsaufgabe. Da der Dienst-Worker nicht ständig ausgeführt wird, besteht keine Gefahr, dass er das System missbraucht, z. B. durch Bitcoin-Mining im Hintergrund.
Auf einigen Plattformen (z. B. Android) kann der Browser nach Schritt 1 geschlossen werden, da er das Abrufen an das Betriebssystem weitergeben kann.
Wenn der Nutzer den Download startet, während er offline ist, oder während des Downloads offline geht, wird der Hintergrundabruf pausiert und später fortgesetzt.
Mit der API
Funktion erkennen
Wie bei jeder neuen Funktion sollten Sie prüfen, ob der Browser sie unterstützt. Für den Hintergrundabruf ist es ganz einfach:
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
Hintergrundabruf starten
Die Haupt-API hängt von einer Service Worker-Registrierung ab. Sie müssen also zuerst einen Service Worker registrieren. Dann:
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
verwendet drei Argumente:
Parameter | |
---|---|
id |
string identifiziert diesen Hintergrundabruf eindeutig.
|
requests |
Array<Request|string>
Die abzurufenden Elemente. Strings werden als URLs behandelt und über new Request(theString) in Request s umgewandelt.
Sie können Daten von anderen Ursprüngen abrufen, sofern die Ressourcen dies über CORS zulassen. Hinweis:Chrome unterstützt derzeit keine Anfragen, für die ein CORS-Preflight erforderlich ist. |
options |
Ein Objekt, das Folgendes enthalten kann: |
options.title |
string Ein Titel, der zusammen mit dem Fortschritt im Browser angezeigt wird. |
options.icons |
Array<IconDefinition> Ein Array von Objekten mit „src“, „size“ und „type“. |
options.downloadTotal |
number Die Gesamtgröße der Antwortkörper (nach dem Entpacken). Diese Angabe ist optional, wird aber dringend empfohlen. Sie gibt dem Nutzer Aufschluss über die Größe des Downloads und den Fortschritt. Wenn Sie diese Angabe nicht machen, wird dem Nutzer im Browser angezeigt, dass die Größe unbekannt ist. Dies kann dazu führen, dass der Nutzer den Download abbricht. Wenn die Anzahl der Downloads im Hintergrund die hier angegebene Zahl überschreitet, wird der Vorgang abgebrochen. Es ist völlig in Ordnung, wenn der Download kleiner als die |
backgroundFetch.fetch
gibt ein Versprechen zurück, das mit einer BackgroundFetchRegistration
aufgelöst wird. Die Details dazu erläutere ich später. Das Versprechen wird abgelehnt, wenn der Nutzer Downloads deaktiviert hat oder einer der angegebenen Parameter ungültig ist.
Wenn Sie viele Anfragen für einen einzelnen Hintergrundabruf stellen, können Sie Dinge kombinieren, die für den Nutzer logischerweise eine Einheit bilden. Ein Film kann beispielsweise in Tausende von Ressourcen aufgeteilt sein (typisch für MPEG-DASH) und zusätzliche Ressourcen wie Bilder enthalten. Ein Level eines Spiels kann auf viele JavaScript-, Bild- und Audioressourcen verteilt werden. Für den Nutzer ist es jedoch nur „der Film“ oder „das Level“.
Vorhandenen Hintergrundabruf abrufen
So rufen Sie einen vorhandenen Hintergrundabruf ab:
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
…indem Sie die ID des gewünschten Hintergrundabrufs übergeben. Für get
wird undefined
zurückgegeben, wenn kein aktiver Hintergrundabruf mit dieser ID vorhanden ist.
Ein Hintergrundabruf gilt ab dem Zeitpunkt der Registrierung als „aktiv“, bis er entweder erfolgreich abgeschlossen, fehlgeschlagen oder abgebrochen wurde.
Mit getIds
können Sie eine Liste aller aktiven Hintergrundabrufe abrufen:
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
Registrierungen für den Hintergrundabruf
Ein BackgroundFetchRegistration
(bgFetch
in den obigen Beispielen) hat Folgendes:
Attribute | |
---|---|
id |
string Die ID des Hintergrundabrufs. |
uploadTotal |
number Die Anzahl der Bytes, die an den Server gesendet werden sollen. |
uploaded |
number Die Anzahl der erfolgreich gesendeten Bytes. |
downloadTotal |
number Der Wert, der beim Registrieren des Hintergrundabrufs angegeben wurde, oder null. |
downloaded |
number Die Anzahl der erfolgreich empfangenen Bytes. Dieser Wert kann sinken. Wenn beispielsweise die Verbindung unterbrochen wird und der Download nicht fortgesetzt werden kann, startet der Browser den Abruf dieser Ressource von vorn. |
result |
Eines der folgenden Betriebssysteme:
|
failureReason |
Eines der folgenden Betriebssysteme:
|
recordsAvailable |
boolean Können die zugrunde liegenden Anfragen/Antworten abgerufen werden? Sobald dies der Fall ist, können |
Methoden | |
abort() |
Gibt Promise<boolean> zurück, um den Hintergrundabruf abzubrechen. Das zurückgegebene Versprechen wird mit „wahr“ abgeschlossen, wenn der Abruf erfolgreich abgebrochen wurde. |
matchAll(request, opts) |
Gibt Promise<Array<BackgroundFetchRecord>> Anfragen und Antworten zurück. Die Argumente sind hier dieselben wie bei der Cache API. Wenn Sie die Funktion ohne Argumente aufrufen, wird ein Versprechen für alle Datensätze zurückgegeben. Weitere Details finden Sie unten. |
match(request, opts) |
Gibt Promise<BackgroundFetchRecord> zurück.Wie oben, wird aber mit der ersten Übereinstimmung aufgelöst. |
Ereignisse | |
progress |
Wird ausgelöst, wenn sich uploaded , downloaded , result oder failureReason ändert. |
Fortschritt verfolgen
Das ist über das Ereignis progress
möglich. Denken Sie daran, dass downloadTotal
der von Ihnen angegebene Wert ist oder 0
, wenn Sie keinen Wert angegeben haben.
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}%`);
});
Anfragen und Antworten abrufen
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
ist eine BackgroundFetchRecord
und sieht so aus:
Attribute | |
---|---|
request |
Request Die Anfrage, die gesendet wurde. |
responseReady |
Promise<Response> Die abgerufene Antwort. Die Antwort ist hinter einem Versprechen, weil sie möglicherweise noch nicht eingegangen ist. Das Versprechen wird abgelehnt, wenn der Abruf fehlschlägt. |
Service Worker-Ereignisse
Ereignisse | |
---|---|
backgroundfetchsuccess |
Alle Daten wurden erfolgreich abgerufen. |
backgroundfetchfailure |
Mindestens eine Abfrage ist fehlgeschlagen. |
backgroundfetchabort |
Mindestens ein Abruf ist fehlgeschlagen.
Das ist nur dann wirklich nützlich, wenn Sie ähnliche Daten bereinigen möchten. |
backgroundfetchclick |
Der Nutzer hat auf die Benutzeroberfläche für den Downloadfortschritt geklickt. |
Die Ereignisobjekte haben folgende Eigenschaften:
Attribute | |
---|---|
registration |
BackgroundFetchRegistration |
Methoden | |
updateUI({ title, icons }) |
Hier können Sie den Titel und die Symbole ändern, die Sie ursprünglich festgelegt haben. Dies ist optional, aber Sie können bei Bedarf mehr Kontext angeben. Sie können dies nur *einmal* bei backgroundfetchsuccess - und backgroundfetchfailure -Ereignissen tun. |
Auf Erfolg oder Misserfolg reagieren
Wir haben das Ereignis progress
bereits kennengelernt. Es ist jedoch nur dann nützlich, wenn der Nutzer eine Seite Ihrer Website geöffnet hat. Der Hauptvorteil des Hintergrundabrufs besteht darin, dass die Inhalte auch dann funktionieren, wenn der Nutzer die Seite verlässt oder sogar den Browser schließt.
Wenn der Abruf im Hintergrund erfolgreich abgeschlossen wurde, erhält Ihr Service Worker das Ereignis backgroundfetchsuccess
. event.registration
ist die Registrierung für den Abruf im Hintergrund.
Nach diesem Ereignis sind die abgerufenen Anfragen und Antworten nicht mehr zugänglich. Wenn Sie sie behalten möchten, verschieben Sie sie an einen anderen Speicherort, z. B. in die Cache API.
Wie bei den meisten Dienstworker-Ereignissen sollten Sie event.waitUntil
verwenden, damit der Dienstworker weiß, wann das Ereignis abgeschlossen ist.
Beispielsweise in Ihrem 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!' });
}());
});
Möglicherweise ist der Fehler auf eine einzelne 404-Antwort zurückzuführen, die für Sie nicht wichtig war. Es kann sich daher trotzdem lohnen, einige Antworten wie oben beschrieben in einen Cache zu kopieren.
Auf Klicks reagieren
Die Benutzeroberfläche mit dem Downloadfortschritt und dem Ergebnis ist anklickbar. Mit dem Ereignis backgroundfetchclick
im Service Worker können Sie darauf reagieren. Wie oben ist event.registration
die Registrierung für den Hintergrundabruf.
Normalerweise wird bei diesem Ereignis ein Fenster geöffnet:
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
Zusätzliche Ressourcen
Korrektur: In einer früheren Version dieses Artikels wurde fälschlicherweise behauptet, dass der Abruf im Hintergrund ein „Webstandard“ ist. Die API befindet sich derzeit nicht im Standards-Track. Die Spezifikation finden Sie im WICG als Community-Gruppenbericht im Entwurf.