Încerci să-ți dai seama ce este un service worker? Nu sunteți singuri!
Un lucrător de servicii este un script care se execută în fundal, într-un fir de execuție separat de interfața de utilizator a browserului. Memoria cache a lucrătorului de servicii face posibil ca un site web să funcționeze offline. Acestea sunt motorul tehnic care ridică nivelul unui site web la o aplicație web progresivă. Ei permit o integrare profundă a platformei, cum ar fi cachingul bogat, notificările push și sincronizarea în fundal.
Service workers sunt concepuți pentru a fi o platformă extensibilă, în prezent sunt planificate caracteristici suplimentare.
Nu pot accesa DOM, dar pot intercepta toate solicitările de rețea. Acest lucru oferă dezvoltatorilor posibilitatea de a controla modul în care sunt gestionate cererile, oferind o modalitate bogată de a face ca site-urile web să funcționeze offline.
Service workers sunt au fost numiți un schimbător de joc pentru web. Nu cred că este o simplă exagerare, deoarece aceștia permit multe capabilități foarte necesare și fac ca arhitectura de bază pe care am folosit-o ani de zile să fie nativă.
Service Workers sună uimitor!
Este tehnologia cheie sau API-ul web modern din spatele aplicațiilor web progresive. Fără un lucrător de servicii, un site web este doar un site web, adăugați un lucrător de servicii și acum aveți o aplicație.
Există câteva caracteristici cheie despre lucrătorii de servicii pe care trebuie să le înțelegeți:
- Un lucrător de servicii este un fișier JavaScript
- Se execută pe un fir de execuție separat de UI
- Nu pot accesa direct DOM
- Există un ciclu de viață sau o serie de evenimente prin care trece un lucrător de servicii pentru a deveni activ, explicat mai târziu
- Sunt vii doar în timp ce sunt folosite, deci nu solicită bateria
- Sunt izolați de originea sau domeniul în care sunt înregistrați
- Service Workers necesită HTTPS
- Pot trimite mesaje către și de la UI
- Nu au nevoie de o pagină web deschisă pentru a funcționa
- Sunt suportați de toate browserele principale, inclusiv iOS Safari
- Sunt similare cu Web Workers, dar mai bune în multe privințe
- Cum funcționează Service Workers?
- Extensibilitatea Service Worker
- Ciclul de viață al Service Worker
- Cât durează Service Workers?
- Cum verific dacă un Service Worker este înregistrat?
- Cum anulez înregistrarea unui lucrător de servicii
- Cașca lucrătorului de servicii
- Cum actualizez memoria cache a lucrătorului meu de servicii
- Ce browsere acceptă lucrătorii de servicii?
- Care este diferența dintre un lucrător de servicii și un lucrător web
- Ce nu poate face un lucrător de servicii
Cum funcționează lucrătorii de servicii?
Un lucrător de servicii se află între browser și rețea, acționând ca un server proxy, gestionând o colecție de sarcini care nu sunt centrate pe interfață. Aceștia sunt orientați pe evenimente și trăiesc în afara procesului browserului, ceea ce le permite să lucreze fără o sesiune activă a browserului. Lucrătorul de servicii este un script care se execută într-un fir de execuție, separat de interfața de utilizator. Acest lucru îi permite lucrătorului de servicii să efectueze sarcini care nu țin de UI, ceea ce face ca un site web să funcționeze mai bine.
Lucrătorii de servicii se termină atunci când nu sunt utilizați și se restabilesc atunci când sunt necesari, acest lucru îi împiedică să suprasolicite CPU și să consume baterii. Aceștia acționează ca un proxy de rețea programabil, sau intermediar între browser și rețea, permițând dezvoltatorilor să proiecteze modul în care sunt gestionate solicitările de rețea.
Prima putere pe care un lucrător de servicii o aduce unui site web este abilitatea de a activa capabilități offline cu control granular. Acest lucru se realizează cu ajutorul unei API bogate de cache și prin interceptarea tuturor cererilor de rețea înainte ca acestea să plece.
Caching nu numai că permite experiențe offline, dar site-urile web se pot încărca instantaneu atunci când sunt recuperate din cache. Memoria cache a lucrătorului de servicii face ca rețeaua să fie o îmbunătățire progresivă sau să nu fie necesară pentru a face site-ul utilizabil.
Extensibilitatea lucrătorului de servicii
O caracteristică subestimată a lucrătorului de servicii este extensibilitatea acestuia Lucrătorii de servicii sunt concepuți pentru a fi coloana vertebrală care suportă funcționalități suplimentare. Primele două funcționalități care se livrează în browsere sunt notificările push native și sincronizarea în fundal. Mai multe API-uri noi sunt în curs de dezbatere și ar trebui să înceapă să apară în browsere în viitorul apropiat.
Service workers trăiesc în propriul lor fir de execuție și nu au acces la DOM. Ei au, de asemenea, propria lor sferă globală, la care se face referire folosind obiectul „self”.
De asemenea, necesită ca un site să fie servit folosind HTTPS. Această cerință se datorează funcțiilor puternice pe care le oferă service workers. HTTPS previne multe atacuri comune. În prezent, toate site-urile ar trebui să fie servite folosind HTTPS, deoarece barierele de implementare au fost ridicate și nivelul minim de securitate pe care îl oferă.
De asemenea, acestea sunt asincrone. Acest lucru înseamnă că toate API-urile acceptă promisiuni. Acest lucru înseamnă, de asemenea, că anumite API-uri și funcții nu sunt accesibile în service workers. Cea mai notabilă este localStorage. În schimb, datele ar trebui să fie stocate folosind IndexedDB.
Service Worker Life Cycle
Înainte de a se scufunda în aceste caracteristici extraordinare ale service worker, dezvoltatorii trebuie să înțeleagă ciclul de viață.
Un service worker trebuie să fie înregistrat de un site web. Deoarece unele browsere încă nu acceptă lucrătorii de servicii, ar trebui să efectuați o verificare a caracteristicilor înainte de a înregistra un lucrător de servicii. Acest lucru se face prin verificarea prezenței lui ‘serviceWorker’ în navigator.
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js') .then(function(registration) { // Registration was successful }) .catch(function(err) { // registration failed :( }); }
Pentru a înregistra lucrătorul de servicii, apelați navigator.serviceWorker.register. Se trece calea către lucrătorul de servicii. Funcția de înregistrare returnează o promisiune.
În caz de succes, promisiunea returnează o referință la obiectul de înregistrare a lucrătorului de servicii. De acolo puteți efectua sarcini specifice de interfață utilizator după cum este necesar.
Evenimente standard ale lucrătorului de servicii
- install
- activate
- fetch
- push (neacceptat de Safari)
- sync (neacceptat încă de majoritatea browserelor)
Când un lucrător de servicii este înregistrat, evenimentul „install”. În acest eveniment, cea mai frecventă sarcină de efectuat se numește pre-caching.
Pre-caching este atunci când o listă predefinită de fișiere de active necesare pentru a forma o pagină sau un site, și le adaugă la cache înainte de a fi solicitate. Acest lucru profită de memoria cache a lucrătorului de servicii pentru a persista aceste răspunsuri.
self.addEventListener("install", event => { event.waitUntil( caches.open(preCacheName) .then(function (cache) { return cache.addAll(precache_urls); }) ); });
Evenimentul de instalare este declanșat doar o singură dată în timpul vieții unui lucrător de servicii. Evenimentul nu se va declanșa din nou până când lucrătorul de servicii nu este actualizat.
Următorul eveniment care se declanșează ca parte a ciclului de viață al înregistrării este „activate”. Atunci când un lucrător de servicii este instalat, acesta nu devine imediat activ. Secvența naturală este ca un nou lucrător de servicii să aștepte până când toți „clienții” lucrătorului de servicii sunt închiși.
Motivul pentru care lucrătorii de servicii sunt concepuți să nu preia imediat controlul este acela de a le împiedica să întrerupă experiența utilizatorului.
Funcția skipWaiting forțează un lucrător de servicii în așteptare să devină activ. Acest lucru ar trebui să fie utilizat numai atunci când sunteți sigur că noul lucrător de servicii nu va întrerupe niciun client existent.
self.skipWaiting();
După ce lucrătorul de servicii devine activ, se declanșează evenimentul „activate”.
self.addEventListener("activate", event => { //on activate event.waitUntil(clients.claim()); });
Acest eveniment este utilizat în mod obișnuit pentru a efectua orice sarcini de curățare sau migrare. De exemplu, eliminarea cache-urilor moștenite care ar putea intra în conflict cu noile cache-uri ale lucrătorului de servicii.
Cât timp durează lucrătorii de servicii?
Nu există o regulă strictă cu privire la cât timp un browser menține în funcțiune un lucrător de servicii. La nivel intern, motorul browserului va folosi un set de euristici pentru a determina când să încheie procesul de lucrător de servicii.
În general, dacă o pagină web este inactivă, procesul se va închide după un minut sau două, poate chiar și după 30 de secunde.
Realitatea este că timpul exact va depinde de hardware, de tiparele de utilizare etc.
Veștile bune sunt că este nevoie de o mână de milisecunde pentru a porni un lucrător de servicii. Este atât de rapid încât nu veți observa cu adevărat nicio latență. De asemenea, nu trebuie să programați nimic special pentru a face față unui scenariu fără lucrătorul de servicii, site-ul dvs. va funcționa pur și simplu. Magia îmbunătățirii progresive.
Cum verific dacă un lucrător de servicii este înregistrat?
Există mai multe moduri de a verifica dacă un lucrător de servicii este înregistrat. Cel mai simplu este să apelați metoda serviceworkers.getRegistrations.
navigator.serviceWorker.getRegistrations().then(registrations => { console.log(registrations); });
Acesta este un cod pe care îl puteți adăuga la scriptul paginilor dvs. pentru a înregistra înregistrarea pentru asistență tehnică sau pentru depanarea dezvoltatorului.
Metoda „getRegistrations” returnează o matrice cu toți lucrătorii de servicii înregistrați în cadrul domeniului de aplicare sau al site-ului web curent.
Dacă doar înregistrați înregistrarea în consolă, ar fi mai bine să vizualizați fila ‘Application’ din Dev Tools. Aceasta are un subpanou care afișează o vizualizare a lucrătorului de servicii înregistrat la origine. Puteți, de asemenea, să declanșați evenimente de sincronizare în fundal și să testați notificările push.
Puteți, de asemenea, să ștergeți lucrătorul de servicii, să forțați o actualizare și alte activități de gestionare generală care ajută la dezvoltare.
Valoarea reală pe care o oferă getRegistrations este pentru un fel de funcție de asistență back-door. Știm cu toții cum este să încerci să ajuți pe cineva de la distanță și să nu poți accesa DevTools pentru a depana cu adevărat problema. Uneori veți dori un fel de pagină de asistență vizuală sau modală pentru a oferi informații despre starea aplicației.
Consumatorul mediu nu va ști cum să acceseze panoul de consolă DevTools. În schimb, puteți crea o interfață utilizator în cadrul aplicației pentru a reda proprietățile obiectului de înregistrare a lucrătorului de servicii.
Cum dezînregistrez un lucrător de servicii
Sperăm că nu veți întâlni un scenariu în care codul lucrătorului de servicii să fi creat o eroare de experiență a utilizatorului. În cazul în care o faceți, există câteva lucruri pe care le puteți face pentru a elimina sau a anula înregistrarea unui lucrător de servicii.
Majoritatea scenariilor în care trebuie să eliminați un lucrător de servicii va fi atunci când dezvoltați aplicația. În acest caz, puteți utiliza DevTools pentru a elimina sau șterge lucrătorul de servicii.
Dacă trebuie să eliminați sau să ștergeți un lucrător de servicii implementat, situația devine puțin mai complicată. Există modalități programatice pentru a vă scoate din încurcătură.
Citește mai multe despre tehnicile de eliminare.
Service Worker Caching
Specificația service worker include capabilități native de caching. Acestea înlocuiesc tradiționalul appCache care a cauzat multe probleme de gestionare de când a fost creat. Memoria cache a lucrătorului de servicii este mult mai ușor de gestionat.
Applicația cache oferă un strat de persistență care stochează răspunsurile din rețea care pot fi interogate de cererea corespunzătoare.
Cheia pentru utilizarea memoriei cache a lucrătorului de servicii este evenimentul „fetch” al lucrătorului de servicii. Acest eveniment se declanșează pentru fiecare cerere de rețea, permițându-vă să interceptați cererea și să verificați dacă răspunsul a fost memorat în memoria cache înainte de a merge în rețea.
Prin accesarea activelor din memoria cache locală puteți renunța la cererile costisitoare din rețea. Acest lucru înseamnă că site-ul poate funcționa atunci când nu există rețea, când este offline sau când există o conectivitate slabă a rețelei, bare joase sau conectivitate celulară falsă (cunoscută sub numele de LiFi).
self.addEventListener("fetch", event => { event.respondWith( fetchFromCache(event) .catch(() => fetch(request) .then(response => addToCache(cacheKey, request, response)) .catch(() => offlineResponse(resourceType, opts)) ) ); });
În exemplul de mai sus, codul verifică dacă un răspuns a fost pus anterior în cache. În caz afirmativ, răspunsul din cache este returnat. În caz contrar, cererea este transmisă către rețea.
Când cererea se întoarce, răspunsul este pus în cache și returnat către UI.
Dacă rețeaua eșuează, logica revine la un răspuns offline.
Există o mulțime de părți mobile utilizate în codul de exemplu. Voi oferi mai multe detalii într-un articol ulterior.
Cum îmi actualizez memoria cache a lucrătorului de servicii
O concepție greșită comună este că odată ce ați pus în cache o cerere de rețea, aceasta este stocată pentru eternitate. Acest lucru nu este cazul. Aveți control complet asupra momentului și modului în care cache-ul este invalidat și actualizat.
Acest subiect este foarte complex și implicat. Cred că pot detalia personal aproximativ 3 duzini de strategii de cache, toate implică o modalitate de a gestiona invalidarea cache-ului sau actualizarea cache-ului.
Cred că cheia invalidării este determinarea fie a unei valori de timp pentru invalidare (time to live), fie a unui manifest sau a unui proces de actualizare în fundal. În cel din urmă, puteți face o cerere HEAD pentru a vedea dacă s-a făcut o actualizare pe server prin compararea valorii ultimului antet actualizat cu momentul în care răspunsul a fost pus în cache.
Nu există un singur răspuns pentru fiecare aplicație. Va trebui să vă planificați strategia și să fiți pregătit să vă adaptați pe măsură ce vedeți cum este folosită aplicația dumneavoastră.
Ce browsere suportă lucrătorii de servicii?
Toate browserele moderne suportă lucrătorii de servicii, cel puțin cache-ul. Chrome, FireFox și Edge suportă notificări push native, iar Chrome și Edge au suport pentru sincronizare în fundal.
Aceasta înseamnă că funcțiile de bază ale PWA sunt disponibile în toate dispozitivele și browserele. Push și sincronizarea în fundal sunt îmbunătățiri.
Am construit mai multe Progressive Web Apps care au necesitat strategii sofisticate de caching offline pentru a permite aplicațiilor să funcționeze offline, chiar și pe iOS. Aceste aplicații necesită ca toate cererile, chiar și acțiunile POST, PUT și DELETE să fie stocate în cache într-o coadă. Am făcut ca aceste aplicații să se sincronizeze chiar și pe iOS atunci când se știa că sunt disponibile conexiuni.
Care este diferența dintre un Service Worker și un Web Worker
Service workers și web workers sunt instrumente similare. Ambele execută procese într-un fir de execuție separat de interfața cu utilizatorul. Adevărata diferență constă în contextul real de utilizare.
Niciunul dintre ei nu are acces la DOM sau la obiectul fereastră. Ele sunt mai bune pentru sarcini de nivel mediu sau pentru sarcini lungi, care necesită un proces intensiv.
Lucrătorii web se execută numai atunci când o pagină web este deschisă și o sarcină este declanșată de un script din pagină.
Un lucrător de servicii se poate executa, de asemenea, atunci când o pagină este deschisă, dar poate fi declanșat și de un eveniment al platformei, cum ar fi o notificare push. O pagină web nu trebuie să fie deschisă pentru ca un lucrător de servicii să se execute.
Lucrătorii de servicii acționează, de asemenea, ca un proxy între rețea și interfața cu utilizatorul. Dacă se utilizează o pagină (cel mai frecvent scenariu), toate solicitările de rețea HTTPS trec prin lucrătorul de servicii, așa cum ați învățat în secțiunea privind memoria cache.
Comunicarea între interfața de utilizator și ambii lucrători se realizează cu ajutorul metodei postMessage și a evenimentului message. Dacă ați făcut programare cu mai multe fire, acest model vă este foarte familiar.
Ce nu poate face un lucrător de servicii
Lucrătorii de servicii nu pot accesa obiectul Window
Obiectul window se execută în firul UI, separat de firul lucrătorului de servicii. Acest lucru înseamnă că un lucrător de servicii nu poate manipula direct elementele DOM. Lucrătorul de servicii și fereastra pot comunica prin intermediul metodei postMessage. Aceasta permite transmiterea mesajelor de la unul la altul. Va trebui să aveți o logică pe fiecare parte pentru a procesa mesajele și a declanșa diferite fluxuri de lucru.
Service Workers Require HTTPS
Pentru că Service Workers au atât de multă putere, acestea sunt activate numai dacă pagina este servită folosind HTTPS. Acest lucru asigură un nivel de securitate pentru a permite lucrătorului de servicii să facă lucrurile pentru care este conceput.
Pe HTTP, lucrătorul de servicii ar fi susceptibil la atacuri de tip „man in the middle”. Dezvoltatorii pot lucra pe localhost, ceea ce ne scutește de instalarea unui certificat TLS local.
Cu alte cuvinte, răspunsul la întrebarea dacă un service worker funcționează pe HTTP este nu. Site-ul va fi în continuare redat, dar lucrătorul de servicii nu se înregistrează și nu este executat.
Sunt doar asincrone
Lucrătorii de servicii sunt asincrone, ceea ce înseamnă că folosesc și se bazează pe Promisiuni și API-uri care folosesc Promisiuni. Acest lucru înseamnă că API-urile sincrone, cum ar fi XHR și localStorage, nu sunt disponibile pentru un lucrător de servicii. Nu vă temeți, puteți utiliza Fetch API (care a înlocuit XHR) și IndexedDB. Majoritatea API-urilor care nu interacționează direct cu obiectul window sunt accesibile într-un service worker.
.