Signatur
Beschreibung
Mit fetch() des BackgroundFetchManager übergibst du große oder lang laufende Downloads, etwa Podcast-Folgen, Videos, Offline-Pakete oder Spiel-Assets, an den Browser. Der Browser führt den Download selbst aus, zeigt dem Nutzer eine Fortschrittsanzeige (z. B. als Benachrichtigung) und macht weiter, auch wenn der Tab geschlossen wird oder die Verbindung kurz abbricht. Erreichbar ist die Methode über ServiceWorkerRegistration.backgroundFetch, also nur, wenn ein Service Worker aktiv ist.
Das zurückgegebene Promise wird mit einer BackgroundFetchRegistration erfüllt. Darüber verfolgst du den Fortschritt (downloaded, downloadTotal, progress-Event) oder brichst den Download mit abort() ab. Ist der Abruf beendet, bekommt der Service Worker eines der Events backgroundfetchsuccess, backgroundfetchfail, backgroundfetchabort oder backgroundfetchclick. Dort liest du die Antworten mit registration.matchAll() aus und legst sie zum Beispiel im Cache Storage ab.
Die id ist ein von dir vergebener, eindeutiger Name. Mit BackgroundFetchManager.get(id) findest du einen laufenden Abruf später wieder, z. B. nach einem Neuladen der Seite. Über options legst du Titel und Symbole für die Anzeige im Browser fest. Außerdem kannst du die erwartete Gesamtgröße angeben, damit der Browser einen genauen Fortschrittsbalken zeigen kann.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $id Pflicht | string | Eindeutiger, von dir vergebener Name für diesen Hintergrundabruf. Läuft bereits ein Abruf mit derselben id, wird das Promise abgelehnt. |
|
| $requests Pflicht | string | Request | Array<string | Request> | Eine URL, ein Request-Objekt oder ein Array davon. Alle Einträge bilden zusammen einen Abruf. Anfragen im Modus no-cors sind nicht erlaubt. |
|
| $options | object | {} | Optionale Einstellungen für die Anzeige im Browser:
|
Rückgabewert
BackgroundFetchRegistration für den gestarteten Abruf erfüllt wird. Es wird mit einem TypeError abgelehnt, wenn kein aktiver Service Worker vorhanden ist, eine Anfrage ungültig ist (z. B. no-cors) oder die id schon benutzt wird. Reicht der Speicherplatz nicht aus, wird es mit einer QuotaExceededError-DOMException abgelehnt.Beispiele
Podcast-Folge im Hintergrund herunterladen
const downloadEpisode = async (episodeId, url) => {
if (!('BackgroundFetchManager' in self)) {
console.log('Background Fetch nicht verfügbar – normaler fetch() als Fallback');
return fetch(url);
}
const swReg = await navigator.serviceWorker.ready;
const bgFetch = await swReg.backgroundFetch.fetch(
`episode-${episodeId}`,
[url],
{
title: 'Folge 42: JavaScript im Hintergrund',
icons: [{ src: '/icons/podcast-192.png', sizes: '192x192', type: 'image/png' }],
downloadTotal: 58 * 1024 * 1024 // 58 MiB
}
);
console.log('Gestartet:', bgFetch.id);
return bgFetch;
};
downloadEpisode(42, '/media/episode-42.mp3');
Fortschritt anzeigen und vorhandenen Abruf wiederverwenden
const startOfflinePack = async () => {
const swReg = await navigator.serviceWorker.ready;
const id = 'offline-pack-v3';
// Nach einem Neuladen nicht doppelt starten
const bgFetch = (await swReg.backgroundFetch.get(id)) ??
await swReg.backgroundFetch.fetch(id, [
'/offline/index.html',
'/offline/app.js',
new Request('/offline/maps.bin', { credentials: 'same-origin' })
], { title: 'Offline-Paket', downloadTotal: 120_000_000 });
bgFetch.addEventListener('progress', () => {
if (!bgFetch.downloadTotal) return;
const percent = Math.round((bgFetch.downloaded / bgFetch.downloadTotal) * 100);
console.log(`Fortschritt: ${percent} %`);
});
};
startOfflinePack().catch((err) => console.error(err.name, err.message));
Ergebnis im Service Worker speichern (sw.js)
self.addEventListener('backgroundfetchsuccess', (event) => {
const bgFetch = event.registration;
event.waitUntil((async () => {
const cache = await caches.open('downloads');
const records = await bgFetch.matchAll();
await Promise.all(records.map(async (record) => {
const response = await record.responseReady;
await cache.put(record.request, response);
}));
await event.updateUI({ title: 'Download abgeschlossen ✔' });
})());
});
self.addEventListener('backgroundfetchfail', (event) => {
event.waitUntil(event.updateUI({ title: 'Download fehlgeschlagen' }));
});
// Wichtig · Fallstricke
- Browser-Unterstützung: Die API ist experimentell und nur in Chromium-Browsern verfügbar (Chrome, Edge, Opera, Samsung Internet). Prüfe vor der Nutzung mit
'BackgroundFetchManager' in selfund sieh einen Ausweg über normalesfetch()vor. - Sicherer Kontext: Die Methode funktioniert nur über HTTPS (oder
localhost) und nur mit einem aktiven Service Worker. Warte deshalb vorher aufnavigator.serviceWorker.ready. - Doppelte IDs: Ein zweiter Aufruf mit einer
id, die gerade läuft, schlägt mit einemTypeErrorfehl. Prüfe vorher mitbackgroundFetch.get(id), ob der Abruf schon existiert. downloadTotal: Ist der Wert zu klein, bricht der Browser den Abruf ab, sobald mehr Bytes ankommen. Gib ihn nur an, wenn du die Größe genau kennst, oder großzügig aufgerundet.- Keine
no-cors-Anfragen: Fremde Ressourcen müssen CORS erlauben. Undurchsichtige Antworten (opaque responses) werden nicht unterstützt. - Datenschutz: Der Browser zeigt laufende Abrufe immer sichtbar an, und der Nutzer kann sie jederzeit abbrechen. Unbemerkte Downloads im Hintergrund sind damit nicht möglich. Plane das Ereignis
backgroundfetchabortmit ein. - Die Antworten werden nicht automatisch zwischengespeichert. Du musst sie im Service Worker selbst, z. B. mit
cache.put(), dauerhaft ablegen.