Servicemedarbejdere er stærke og absolut værd at lære. De giver dig mulighed for at levere et helt nyt niveau af oplevelse til dine brugere. Dit websted kan indlæses med det samme. Det kan fungere offline. Det kan installeres som en native app og føles lige så poleret – men med den rækkevidde og frihed, som internettet har.

Men service workers ligner ikke noget, som de fleste af os webudviklere er vant til. De kommer med en stejl indlæringskurve og en håndfuld hakker, som du skal passe på.

Google Developers og jeg samarbejdede for nylig om et projekt – Service Workies – et gratis spil til at forstå service workers. Mens jeg byggede det og arbejdede med de komplekse ins og outs af service workers, løb jeg ind i et par snags. Det, der hjalp mig mest, var at komme op med en håndfuld beskrivende metaforer. I dette indlæg vil vi udforske disse mentale modeller og pakke vores hjerner ind i de paradoksale træk, der gør servicemedarbejdere både vanskelige og fantastiske.

Det samme, men anderledes #

Mens du koder din servicemedarbejder, vil mange ting føles velkendte. Du får mulighed for at bruge dine nye yndlingsfunktioner i JavaScript-sproget. Du lytter til livscyklushændelser ligesom med UI-hændelser. Du styrer kontrolflowet med promises, som du er vant til.

Men anden service worker-adfærd får dig til at klø dig i hovedet i forvirring. Især når du opdaterer siden og ikke kan se, at dine kodeændringer er blevet anvendt.

Et nyt lag #

Normalt har du kun to lag at tænke på, når du bygger et websted: klienten og serveren. Tjenestearbejderen er et helt nyt lag, der ligger i midten.

Tænk på din tjenestearbejder som en slags browserudvidelse – en, som dit websted kan installere i din brugers browser. Når servicemedarbejderen er installeret, udvider den browseren for dit websted med et kraftfuldt mellemlag. Dette servicemedarbejderlag kan opfange og håndtere alle de anmodninger, som dit websted foretager.

Servicemedarbejderlaget har sin egen livscyklus, der er uafhængig af browserfanen. En simpel sideopdatering er ikke nok til at opdatere en service worker – ligesom du heller ikke ville forvente, at en sideopdatering ville opdatere kode, der er implementeret på en server. Hvert lag har sine egne unikke regler for opdatering.

I spillet Service Workies dækker vi de mange detaljer i service workers livscyklus og giver dig masser af øvelse i at arbejde med det.

Tænk på din service worker som et nyt mellemlag med sin egen livscyklus og metoder til opdatering.

Kraftig, men begrænset #

Det giver dig utrolige fordele at have en service worker på dit websted. Dit websted kan:

  • fungere fejlfrit, selv når brugeren er offline
  • få massive ydelsesforbedringer gennem caching
  • bruge push-meddelelser
  • blive installeret som en PWA

Så meget som service workers kan gøre, er de begrænset af design. De kan ikke gøre noget synkront eller i den samme tråd som dit websted. Det betyder altså ingen adgang til:

  • localStorage
  • the DOM
  • the window

Den gode nyhed er, at der er en håndfuld måder, hvorpå din side kan kommunikere med sin service worker, herunder direkte postMessage, en-til-en Message Channels og en-til-mange Broadcast Channels.

Tænk på din service worker som noget, der bor uden for din side. Du kan tale med den, men den kan ikke få direkte adgang til din side.

Lang levetid, men kort levetid #

En aktiv servicemedarbejder fortsætter med at leve, selv efter at en bruger forlader dit websted eller lukker fanen. Browseren beholder denne servicemedarbejder, så den er klar, næste gang brugeren kommer tilbage til dit websted. Inden den allerførste forespørgsel bliver foretaget, får servicearbejderen en chance for at opfange den og overtage kontrollen med siden. Det er det, der gør det muligt for et websted at fungere offline – servicearbejderen kan selv servere en cached version af siden, selv om brugeren ikke har nogen forbindelse til internettet.

I Service Workies visualiserer vi dette koncept med Kolohe (en venlig servicearbejder), der opsnapper og håndterer anmodninger.

Stopped #

Selv om servicearbejderne ser ud til at være udødelige, kan de stoppes næsten når som helst. Browseren ønsker ikke at spilde ressourcer på en service worker, der ikke foretager sig noget i øjeblikket. At blive stoppet er ikke det samme som at blive opsagt – servicearbejderen forbliver installeret og aktiveret. Den bliver bare sat i dvale. Næste gang der er brug for den (f.eks. for at håndtere en anmodning), vækker browseren den igen.

waitUntil #

På grund af den konstante mulighed for at blive sat i dvale har din servicemedarbejder brug for en måde at lade browseren vide, hvornår den er i gang med noget vigtigt og ikke har lyst til at tage en lur. Det er her, at event.waitUntil() kommer ind i billedet. Denne metode udvider den livscyklus, den bruges i, og forhindrer den både i at blive stoppet og i at gå videre til den næste fase af dens livscyklus, indtil vi er klar. Det giver os tid til at oprette caches, hente ressourcer fra netværket osv.

Dette eksempel fortæller browseren, at vores service worker ikke er færdig med at installere, før assets-cachen er oprettet og fyldt op med billedet af et sværd:

self.addEventListener("install", event => {
event.waitUntil(
caches.open("assets").then(cache => {
return cache.addAll();
})
);
});

Opmærksom på global tilstand #

Når denne start/stop sker, nulstilles service worker’s globale omfang. Så pas på ikke at bruge nogen global tilstand i din service worker, ellers bliver du ked af det næste gang den vågner op igen og har en anden tilstand end den forventede.

Se på dette eksempel, der bruger en global tilstand:

const favoriteNumber = Math.random();
let hasHandledARequest = false;
self.addEventListener("fetch", event => {
console.log(favoriteNumber);
console.log(hasHandledARequest);
hasHandledARequest = true;
});

På hver anmodning vil denne service worker logge et nummer – lad os sige 0.13981866382421893. Variablen hasHandledARequest ændres også til true. Nu sidder servicearbejderen stille i et stykke tid, så browseren stopper den. Næste gang der er en anmodning, er der brug for servicearbejderen igen, så browseren vækker den op. Dens script evalueres igen. Nu er hasHandledARequest nulstillet til false, og favoriteNumber er noget helt andet – 0.5907281835659033.

Du kan ikke stole på lagret tilstand i en service worker. Desuden kan oprettelse af instanser af ting som Message Channels forårsage fejl: Du får en helt ny instans, hver gang servicearbejderen stopper/starter.

Varsling: Denne hage er særlig vigtig at huske på, når du arbejder på din service worker-kode, fordi når Chrome DevTools er åben, er start/stop-adfærden deaktiveret. Du kan måske ikke engang se fejl forårsaget af at stole på global tilstand, før de er blevet sendt til dine brugere.

I Service Workies kapitel 3 visualiserer vi vores stoppede service worker som værende ved at miste al farve, mens den venter på at blive vækket.

Tænk på din service worker som en pisket hund. Den er hurtig, loyal og fantastisk. Den vil holde sig ved din side, uanset hvad der sker. Men for det meste vil den bare gerne sove. Hele tiden. Du er nødt til at lade den vide, hvornår du vil have den til at holde sig vågen. God hund!

Sammen, men adskilt #

Din side kan kun styres af én servicemedarbejder ad gangen. Men den kan have to service workers installeret på samme tid. Når du foretager en ændring i din service worker-kode og opdaterer siden, redigerer du faktisk slet ikke din service worker. Service workers er uforanderlige. Du laver i stedet en helt ny. Denne nye service worker (lad os kalde den SW2) vil blive installeret, men den vil ikke blive aktiveret endnu. Den skal vente på, at den nuværende service worker (SW1) afsluttes (når din bruger forlader dit websted).

Menger med en anden service workers caches #

Mens SW2 installerer, kan den få ting sat op – normalt oprette og udfylde caches. Men pas på: Denne nye servicemedarbejder har adgang til alt det, som den nuværende servicemedarbejder har adgang til. Hvis du ikke er forsigtig, kan din nye ventende servicemedarbejder virkelig ødelægge tingene for din nuværende servicemedarbejder. Nogle eksempler, der kan give dig problemer:

  • SW2 kan slette en cache, som SW1 bruger aktivt.
  • SW2 kan redigere indholdet af en cache, som SW1 bruger, hvilket får SW1 til at svare med aktiver, som siden ikke forventer.

Skip skipWaiting #

En servicemedarbejder kan også bruge den risikable skipWaiting() metode til at overtage kontrollen over siden, så snart den er færdig med at installere. Dette er generelt en dårlig idé, medmindre du med vilje forsøger at erstatte en fejlbehæftet servicearbejder. Den nye service worker bruger måske opdaterede ressourcer, som den aktuelle side ikke forventer, hvilket fører til fejl og fejl.

Start rent #

Måden at forhindre, at dine service workers overdøver hinanden, er at sørge for, at de bruger forskellige caches. Den nemmeste måde at opnå det på er at versionere de cachenavne, de bruger.

const version = 1;
const assetCacheName = `assets-${version}`;
self.addEventListener("install", event => {
caches.open(assetCacheName).then(cache => {
// confidently do stuff with your very own cache
});
});

Når du implementerer en ny servicemedarbejder, skal du bumpe version, så den gør det, den har brug for, med en helt separat cache fra den tidligere servicemedarbejder.

End clean #

Når din servicemedarbejder når tilstanden activated, ved du, at den har taget over, og at den tidligere servicemedarbejder er overflødig (dvs, ikke længere er nødvendig). På dette tidspunkt er det vigtigt at rydde op efter den gamle service worker. Ikke alene respekterer det dine brugeres cache-lagringsgrænser, men det kan også forhindre utilsigtede fejl.

Metoden caches.match() er en ofte anvendt genvej til at hente et element fra enhver cache, hvor der er et match. Men den gennemløber cacherne i den rækkefølge, de blev oprettet. Så lad os sige, at du har to versioner af en scriptfil app.js i to forskellige caches – assets-1 og assets-2. Din side forventer det nyere script, der er gemt i assets-2. Men hvis du ikke har slettet den gamle cache, vil caches.match('app.js') returnere den gamle version fra assets-1 og højst sandsynligt ødelægge dit websted.

Det eneste, der skal til for at rydde op efter tidligere service workers, er at slette al cache, som den nye service worker ikke har brug for:

const version = 2;
const assetCacheName = `assets-${version}`;
self.addEventListener("activate", event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== assetCacheName){
return caches.delete(cacheName);
}
});
);
});
);
});

Forebyggelse af, at dine service workers ikke klynger sig til hinanden, kræver en smule arbejde og disciplin, men er besværet værd.

Tænk på kombinationen af din service worker og dit websted som en installerbar app. Hver version bør fungere. Hver version skal være adskilt fra de andre. Forestil dig, hvor fejlbehæftet et spil ville være, hvis udvikleren ved et uheld frigav en patch, der brugte ny spillogik, men forældede aktiver. Du ville rase på forummet så hurtigt! Hold dine app-versioner ryddelige & rene.

Servicearbejder-tankegang #

Gå ind i den rigtige tankegang, mens du tænker på servicearbejdere, vil hjælpe dig med at opbygge dine med selvtillid. Når du først får styr på dem, vil du være i stand til at skabe utrolige oplevelser for dine brugere.

Hvis du vil forstå alt dette ved at spille et spil, så er du heldig! Gå ud og spil Service Workies, hvor du lærer servicemedarbejderens metoder for at dræbe de offline bæster.

Sidst opdateret: Forbedre artikel

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.