Utforsk hvordan Service Workers avskjærer forespørsler om sideinnlasting, og muliggjør hurtigbufferstrategier, offline-funksjonalitet og forbedret ytelse for moderne webapplikasjoner.
Frontend Service Worker-navigasjon: Avskjæring av sideinnlastinger for en forbedret brukeropplevelse
Service Workers er en kraftig teknologi som lar deg avskjære nettverksforespørsler, hurtigbufre ressurser og tilby offline-funksjonalitet for webapplikasjoner. En av de mest virkningsfulle egenskapene er å avskjære forespørsler om sideinnlasting, noe som lar deg dramatisk forbedre ytelse og brukeropplevelse. Dette innlegget vil utforske hvordan Service Workers håndterer navigasjonsforespørsler, med praktiske eksempler og handlingsrettet innsikt for utviklere.
Forstå navigasjonsforespørsler
Før vi dykker ned i koden, la oss definere hva en "navigasjonsforespørsel" er i konteksten av Service Workers. En navigasjonsforespørsel er en forespørsel initiert av brukeren som navigerer til en ny side eller oppdaterer den nåværende siden. Disse forespørslene utløses vanligvis av:
- Klikke på en lenke (
<a>-tagg) - Skrive inn en URL i adressefeltet
- Oppdatere siden
- Bruke nettleserens tilbake- eller fremoverknapper
Service Workers har muligheten til å avskjære disse navigasjonsforespørslene og bestemme hvordan de skal håndteres. Dette åpner for muligheter til å implementere sofistikerte hurtigbufferstrategier, levere innhold fra hurtigbufferen når brukeren er offline, og til og med dynamisk generere sider på klientsiden.
Registrere en Service Worker
Det første steget er å registrere en Service Worker. Dette gjøres vanligvis i din hoved-JavaScript-fil:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('Service Worker registrert med scope:', registration.scope);
})
.catch(error => {
console.error('Service Worker-registrering feilet:', error);
});
}
Denne koden sjekker om nettleseren støtter Service Workers, og hvis den gjør det, registrerer den /service-worker.js-filen. Sørg for at denne JavaScripten kjøres i en sikker kontekst (HTTPS) for produksjonsmiljøer.
Avskjære navigasjonsforespørsler i Service Worker
Inne i din service-worker.js-fil kan du lytte etter fetch-hendelsen. Denne hendelsen utløses for hver nettverksforespørsel som applikasjonen din gjør, inkludert navigasjonsforespørsler. Vi kan filtrere disse forespørslene for å håndtere navigasjonsforespørsler spesifikt.
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(async () => {
try {
// Først, prøv å bruke navigation preload-responsen hvis den støttes.
const preloadResponse = await event.preloadResponse;
if (preloadResponse) {
return preloadResponse;
}
// Prøv alltid nettverket først.
const networkResponse = await fetch(event.request);
return networkResponse;
} catch (error) {
// catch utløses kun hvis et unntak kastes, noe som sannsynligvis
// skyldes en nettverksfeil.
// Hvis henting av HTML-filen feiler, se etter en fallback.
console.log('Henting feilet; returnerer offline-side i stedet.', error);
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(OFFLINE_URL);
return cachedResponse || createErrorResponse(); // Fallback hvis offline-siden ikke er tilgjengelig
}
});
}
});
La oss bryte ned denne koden:
event.request.mode === 'navigate': Denne betingelsen sjekker om forespørselen er en navigasjonsforespørsel.event.respondWith(): Denne metoden forteller nettleseren hvordan den skal håndtere forespørselen. Den tar et promise som resolverer til etResponse-objekt.event.preloadResponse: Dette er en mekanisme kalt Navigation Preload. Hvis den er aktivert, lar den nettleseren begynne å hente navigasjonsforespørselen før Service Worker-en er fullt aktiv. Det gir en hastighetsforbedring ved å overlappe oppstartstiden til Service Worker med nettverksforespørselen.fetch(event.request): Dette henter ressursen fra nettverket. Hvis nettverket er tilgjengelig, vil siden lastes fra serveren som normalt.caches.open(CACHE_NAME): Dette åpner en hurtigbuffer med det angitte navnet (CACHE_NAMEmå være definert et annet sted i Service Worker-filen din).cache.match(OFFLINE_URL): Dette ser etter en bufret respons som matcherOFFLINE_URL(f.eks. en offline-side).createErrorResponse(): Dette er en tilpasset funksjon som returnerer en feilrespons. Du kan tilpasse denne funksjonen for å gi en brukervennlig offline-opplevelse.
Hurtigbufferstrategier for navigasjonsforespørsler
Det forrige eksempelet demonstrerer en grunnleggende nettverk-først-strategi. Du kan imidlertid implementere mer sofistikerte hurtigbufferstrategier avhengig av applikasjonens krav.
Nettverk først, med fallback til hurtigbuffer
Dette er strategien som ble vist i det forrige eksempelet. Den prøver å hente ressursen fra nettverket først. Hvis nettverksforespørselen feiler (f.eks. brukeren er offline), faller den tilbake til hurtigbufferen. Dette er en god strategi for innhold som oppdateres ofte.
Hurtigbuffer først, oppdatering i bakgrunnen
Denne strategien sjekker hurtigbufferen først. Hvis ressursen finnes i hurtigbufferen, returneres den umiddelbart. I bakgrunnen oppdaterer Service Worker-en hurtigbufferen med den nyeste versjonen av ressursen fra nettverket. Dette gir en rask initiell innlasting og sikrer at brukeren til slutt alltid har det nyeste innholdet.
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(
caches.match(event.request)
.then(cachedResponse => {
if (cachedResponse) {
// Oppdater hurtigbufferen i bakgrunnen.
event.waitUntil(
fetch(event.request).then(response => {
return caches.open(CACHE_NAME).then(cache => {
return cache.put(event.request, response.clone());
});
})
);
return cachedResponse;
}
// Hvis ikke funnet i hurtigbuffer, hent fra nettverket.
return fetch(event.request);
})
);
}
});
Kun hurtigbuffer
Denne strategien serverer kun innhold fra hurtigbufferen. Hvis ressursen ikke finnes i hurtigbufferen, feiler forespørselen. Dette passer for ressurser som er kjent for å være statiske og tilgjengelige offline.
Stale-While-Revalidate
Ligner på Hurtigbuffer først, men i stedet for å oppdatere i bakgrunnen med event.waitUntil, returnerer du umiddelbart den bufrede responsen (hvis tilgjengelig) og *alltid* prøver å hente den nyeste versjonen fra nettverket og oppdatere hurtigbufferen. Denne tilnærmingen gir en veldig rask initiell innlasting, ettersom brukeren får den bufrede versjonen umiddelbart, men den garanterer at hurtigbufferen til slutt vil bli oppdatert med de ferskeste dataene, klare for neste forespørsel. Dette er utmerket for ikke-kritiske ressurser eller situasjoner der det er akseptabelt å vise litt utdatert informasjon i en kort periode i bytte mot hastighet.
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(
caches.open(CACHE_NAME).then(cache => {
return cache.match(event.request).then(cachedResponse => {
const fetchedResponse = fetch(event.request).then(networkResponse => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
});
// Returner den bufrede responsen hvis vi har den, ellers vent
// på nettverket.
return cachedResponse || fetchedResponse;
});
})
);
}
});
Navigasjon-forhåndslasting (Navigation Preload)
Navigation Preload er en funksjon som lar nettleseren begynne å hente ressursen før Service Worker-en er fullt aktiv. Dette kan forbedre ytelsen til navigasjonsforespørsler betydelig, spesielt ved første besøk på nettstedet ditt.
For å aktivere Navigation Preload, må du:
- Aktivere det i
activate-hendelsen til din Service Worker. - Sjekke for
preloadResponseifetch-hendelsen.
// I activate-hendelsen:
self.addEventListener('activate', event => {
event.waitUntil(self.registration.navigationPreload.enable());
});
// I fetch-hendelsen (som vist i det første eksempelet):
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(async () => {
const preloadResponse = await event.preloadResponse;
if (preloadResponse) {
return preloadResponse;
}
// ... resten av din fetch-logikk ...
});
}
});
Håndtering av offline-scenarioer
En av de primære fordelene ved å bruke Service Workers er muligheten til å tilby offline-funksjonalitet. Når brukeren er offline, kan du servere en bufret versjon av applikasjonen din eller vise en tilpasset offline-side.
For å håndtere offline-scenarioer, må du:
- Hurtigbufre de nødvendige ressursene, inkludert HTML, CSS, JavaScript og bilder.
- I
fetch-hendelsen, fange opp eventuelle nettverksfeil og servere en bufret offline-side.
// Definer URL for offline-siden og navn på hurtigbuffer
const OFFLINE_URL = '/offline.html';
const CACHE_NAME = 'my-app-cache-v1';
// Install-hendelse: hurtigbufre statiske ressurser
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
return cache.addAll([
'/',
'/index.html',
'/style.css',
'/app.js',
OFFLINE_URL // Hurtigbufre offline-siden
]);
})
);
self.skipWaiting(); // Aktiver service worker umiddelbart
});
// Fetch-hendelse: håndter navigasjonsforespørsler og offline-fallback
self.addEventListener('fetch', event => {
if (event.request.mode === 'navigate') {
event.respondWith(async () => {
try {
// Først, prøv å bruke navigation preload-responsen hvis den støttes.
const preloadResponse = await event.preloadResponse;
if (preloadResponse) {
return preloadResponse;
}
// Prøv alltid nettverket først.
const networkResponse = await fetch(event.request);
return networkResponse;
} catch (error) {
// catch utløses kun hvis et unntak kastes, noe som sannsynligvis
// skyldes en nettverksfeil.
// Hvis henting av HTML-filen feiler, se etter en fallback.
console.log('Henting feilet; returnerer offline-side i stedet.', error);
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(OFFLINE_URL);
return cachedResponse || createErrorResponse(); // Fallback hvis offline-siden ikke er tilgjengelig
}
});
}
});
function createErrorResponse() {
return new Response(
`Offline
Du er for øyeblikket offline. Vennligst sjekk internettforbindelsen din.
`, {
headers: { 'Content-Type': 'text/html' }
}
);
}
Denne koden bufrer en offline.html-side under install-hendelsen. Deretter, i fetch-hendelsen, hvis nettverksforespørselen feiler (catch-blokken kjøres), sjekker den hurtigbufferen for offline.html-siden og returnerer den til nettleseren.
Avanserte teknikker og hensyn
Bruke Cache Storage API direkte
caches-objektet gir et kraftig API for å administrere bufrede responser. Du kan bruke metoder som cache.put(), cache.match(), og cache.delete() for å manipulere hurtigbufferen direkte. Dette gir deg finkornet kontroll over hvordan ressurser bufres og hentes.
Dynamisk hurtigbuffring
I tillegg til å bufre statiske ressurser, kan du også bufre dynamisk innhold, som for eksempel API-responser. Dette kan forbedre ytelsen til applikasjonen din betydelig, spesielt for brukere med trege eller upålitelige internettforbindelser.
Versjonering av hurtigbuffer
Det er viktig å versjonere hurtigbufferen din slik at du kan oppdatere de bufrede ressursene når applikasjonen din endres. En vanlig tilnærming er å inkludere et versjonsnummer i CACHE_NAME. Når du oppdaterer applikasjonen din, kan du øke versjonsnummeret, noe som vil tvinge nettleseren til å laste ned de nye ressursene.
const CACHE_NAME = 'my-app-cache-v2'; // Øk versjonsnummeret
Du må også fjerne gamle hurtigbuffere for å forhindre at de akkumuleres og kaster bort lagringsplass. Du kan gjøre dette i activate-hendelsen.
self.addEventListener('activate', event => {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
Bakgrunnssynkronisering (Background Sync)
Service Workers tilbyr også Background Sync API, som lar deg utsette oppgaver til brukeren har en stabil internettforbindelse. Dette er nyttig for scenarioer som å sende inn skjemaer eller laste opp filer når brukeren er offline.
Push-varsler
Service Workers kan også brukes til å implementere push-varsler, som lar deg sende meldinger til brukerne dine selv når de ikke aktivt bruker applikasjonen din. Dette kan brukes til å varsle brukere om nytt innhold, oppdateringer eller viktige hendelser.
Hensyn til internasjonalisering (i18n) og lokalisering (L10n)
Når man implementerer Service Workers i en global applikasjon, er det avgjørende å ta hensyn til internasjonalisering (i18n) og lokalisering (L10n). Her er noen nøkkelaspekter:
- Språkdeteksjon: Implementer en mekanisme for å oppdage brukerens foretrukne språk. Dette kan innebære å bruke
Accept-LanguageHTTP-headeren, en brukerinnstilling, eller nettleser-APIer. - Lokalisert innhold: Lagre lokaliserte versjoner av dine offline-sider og annet bufret innhold. Bruk det oppdagede språket til å servere den riktige versjonen. For eksempel kan du ha separate offline-sider for engelsk (
/offline.en.html), spansk (/offline.es.html) og fransk (/offline.fr.html). Din Service Worker vil da dynamisk velge den riktige filen å bufre og servere basert på brukerens språk. - Dato- og tidsformatering: Sørg for at eventuelle datoer og klokkeslett som vises på dine offline-sider, er formatert i henhold til brukerens locale. Bruk JavaScripts
Intl-API til dette formålet. - Valutaformatering: Hvis applikasjonen din viser valutaverdier, formater dem i henhold til brukerens locale og valuta. Igjen, bruk
Intl-APIet for valutaformatering. - Tekstretning: Vurder språk som leses fra høyre til venstre (RTL), som arabisk og hebraisk. Dine offline-sider og bufrede innhold bør støtte RTL-tekstretning ved hjelp av CSS.
- Ressursinnlasting: Last inn lokaliserte ressurser (f.eks. bilder, fonter) dynamisk basert på brukerens språk.
Eksempel: Valg av lokalisert offline-side
// Funksjon for å hente brukerens foretrukne språk
function getPreferredLanguage() {
// Dette er et forenklet eksempel. I en ekte applikasjon,
// ville du brukt en mer robust mekanisme for språkdeteksjon.
return navigator.language || navigator.userLanguage || 'en';
}
// Definer en mapping av språk til URL-er for offline-sider
const offlinePageUrls = {
'en': '/offline.en.html',
'es': '/offline.es.html',
'fr': '/offline.fr.html'
};
// Hent brukerens foretrukne språk
const preferredLanguage = getPreferredLanguage();
// Bestem URL-en for offline-siden basert på det foretrukne språket
let offlineUrl = offlinePageUrls[preferredLanguage] || offlinePageUrls['en']; // Fallback til engelsk hvis det ikke er noen match
// ... resten av din service worker-kode, som bruker offlineUrl for å bufre og servere den riktige offline-siden ...
Testing og feilsøking
Testing og feilsøking av Service Workers kan være utfordrende. Her er noen tips:
- Bruk Chrome DevTools: Chrome DevTools har et dedikert panel for å inspisere Service Workers. Du kan bruke dette panelet til å se statusen til din Service Worker, inspisere bufrede ressurser og feilsøke nettverksforespørsler.
- Bruk "Update on reload" for Service Worker: I Chrome DevTools -> Application -> Service Workers, kan du krysse av for "Update on reload" for å tvinge service workeren til å oppdatere ved hver sideinnlasting. Dette er ekstremt nyttig under utvikling.
- Tøm lagring: Noen ganger kan en Service Worker havne i en dårlig tilstand. Å tømme nettleserens lagring (inkludert hurtigbufferen) kan bidra til å løse disse problemene.
- Bruk et testbibliotek for Service Worker: Det finnes flere biblioteker som kan hjelpe deg med å teste dine Service Workers, som for eksempel Workbox.
- Test på ekte enheter: Selv om du kan teste Service Workers i en stasjonær nettleser, er det viktig å teste på ekte mobile enheter for å sikre at de fungerer korrekt under forskjellige nettverksforhold.
Konklusjon
Å avskjære forespørsler om sideinnlasting med Service Workers er en kraftig teknikk for å forbedre brukeropplevelsen i webapplikasjoner. Ved å implementere hurtigbufferstrategier, tilby offline-funksjonalitet og optimalisere nettverksforespørsler, kan du betydelig forbedre ytelse og engasjement. Husk å ta hensyn til internasjonalisering når du utvikler for et globalt publikum for å sikre en konsistent og brukervennlig opplevelse for alle.
Denne guiden gir et solid grunnlag for å forstå og implementere avskjæring av navigasjon med Service Worker. Etter hvert som du fortsetter å utforske denne teknologien, vil du oppdage enda flere måter å utnytte dens kapabiliteter for å skape eksepsjonelle webopplevelser.