Dowiedz się, czym są Web Workery i Service Workery, jak się różnią i kiedy użyć każdego z nich, by przyspieszyć stronę, wykonywać zadania w tle, cache'ować i zapewnić wsparcie offline.

Przeglądarki uruchamiają większość twojego JavaScriptu na wątku głównym — tym samym, który obsługuje wejście użytkownika, animacje i rysowanie strony. Gdy na tym wątku wykonywana jest ciężka praca (parsowanie dużych danych, przetwarzanie obrazów, złożone obliczenia), interfejs może przycinać lub „zawieszać się”. Workery istnieją po to, by przenieść pewne zadania z wątku głównego lub poza bezpośrednią kontrolę strony, tak aby twoja aplikacja pozostała responsywna.
Jeśli twoja strona zajęta jest 200ms obliczeniami, przeglądarka nie może płynnie przewijać, odpowiadać na kliknięcia ani utrzymywać animacji na 60fps. Workery pomagają, pozwalając wykonywać pracę w tle, podczas gdy wątek główny zajmuje się interfejsem.
A Web Worker to tleowy wątek JavaScript, który tworzysz z poziomu strony. Jest najlepszy do zadań obciążających CPU, które w innym wypadku zablokowałyby UI.
A Service Worker to specjalny rodzaj workera, który stoi między twoją aplikacją webową a siecią. Może przechwytywać żądania, cache'ować odpowiedzi i umożliwiać funkcje takie jak wsparcie offline czy powiadomienia push.
Pomyśl o Web Workerze jak o pomocniku wykonującym obliczenia w innym pokoju. Wysyłasz mu wiadomość, on pracuje i odsyła odpowiedź.
Pomyśl o Service Workerze jak o strażniku przy drzwiach. Żądania stron, skryptów i API przechodzą obok niego i on może zdecydować, czy pobrać z sieci, podać z cache czy odpowiedzieć w niestandardowy sposób.
Na końcu będziesz wiedzieć:
postMessage) pasuje do modelu workerów i dlaczego Cache Storage API jest ważne dla offlineTo podsumowanie ustawia „dlaczego” i model mentalny — dalej zagłębimy się w zachowanie każdego typu workera i gdzie pasuje w realnych projektach.
Kiedy otwierasz stronę, większość tego, co „odczuwasz”, dzieje się na wątku głównym. Odpowiada on za rysowanie pikseli (rendering), reagowanie na dotknięcia i kliknięcia (input) oraz uruchamianie dużej części JavaScriptu.
Ponieważ renderowanie, obsługa wejścia i JavaScript często korzystają z tego samego wątku, jedno wolne zadanie może sprawić, że wszystko inne będzie czekać. Dlatego problemy wydajności zwykle objawiają się jako problemy z responsywnością, nie tylko „wolny kod”.
Co użytkownik odczuwa jako „blokowanie":
JavaScript ma wiele asynchronicznych API — fetch(), timery, zdarzenia — które pomagają unikać bezczynnego czekania. Ale asynchroniczność nie sprawia magicznie, że ciężka praca wykona się jednocześnie z renderowaniem.
Jeśli wykonujesz drogie obliczenia (przetwarzanie obrazów, parsowanie dużego JSONa, kryptografia, złożone filtrowanie) na wątku głównym, nadal konkurują one z aktualizacjami UI. „Async” może opóźnić kiedy coś się uruchomi, ale wciąż może wykonać się na tym samym wątku i powodować jank.
Workery istnieją po to, by przeglądarki mogły zachować responsywność strony, wykonując jednocześnie znaczącą pracę.
W skrócie: workery chronią wątek główny, dzięki czemu aplikacja pozostaje interaktywna, wykonując rzeczywistą pracę w tle.
A Web Worker to sposób uruchamiania JavaScriptu poza wątkiem głównym. Zamiast konkurować z pracą UI (renderowanie, przewijanie, reagowanie na kliknięcia), worker działa we własnym wątku w tle, więc ciężkie zadania mogą zakończyć się bez „zawieszania” strony.
Pomyśl o tym tak: strona skupia się na interakcjach użytkownika, a worker zajmuje się pracami obciążającymi CPU, jak parsowanie dużego pliku, obliczenia czy przygotowanie danych do wykresów.
Web Worker działa w oddzielnym wątku z własnym zakresem globalnym. Nadal ma dostęp do wielu web API (timery, fetch w wielu przeglądarkach, crypto itd.), ale jest celowo odizolowany od strony.
Istnieją parę popularnych wariantów:
Jeśli nigdy nie korzystałeś z workerów, większość przykładów, które zobaczysz, dotyczy Dedicated Workera.
Workery nie wywołują bezpośrednio funkcji na stronie. Zamiast tego komunikacja odbywa się przez wysyłanie wiadomości:
postMessage().postMessage().Dla dużych binarnych danych można często poprawić wydajność, transferując własność ArrayBuffer (aby nie był kopiowany), co utrzymuje przekazywanie wiadomości szybkie.
Ponieważ worker jest odizolowany, istnieje kilka kluczowych ograniczeń:
window ani document. Workery działają pod self (globalnym zakresem workera), a dostępne API mogą różnić się od tych na stronie.Dobrze użyty Web Worker to jeden z najprostszych sposobów poprawy wydajności wątku głównego bez zmiany zachowania aplikacji — tylko zmieniasz miejsce wykonywania ciężkiej pracy.
Web Workery pasują świetnie, gdy twoja strona „zawiesza się”, ponieważ JavaScript wykonuje zbyt dużo pracy na wątku głównym. Wątek główny odpowiada też za interakcje użytkownika i renderowanie, więc ciężkie zadania tam mogą powodować jank, opóźnione kliknięcia i zamrożone przewijanie.
Użyj Web Workera, gdy masz prace obciążające CPU, które nie potrzebują bezpośredniego dostępu do DOM:
Praktyczny przykład: jeśli otrzymujesz duży payload JSON i jego parsowanie powoduje przycinanie UI, przenieś parsowanie do workera, a potem odeślij wynik.
Komunikacja z workerem odbywa się przez postMessage. Dla dużych danych binarnych preferuj transferable objects (jak ArrayBuffer), aby przeglądarka mogła przekazać własność pamięci do workera zamiast ją kopiować.
// main thread
worker.postMessage(buffer, [buffer]); // transfers the ArrayBuffer
To jest szczególnie przydatne dla buforów audio, bajtów obrazu lub innych dużych fragmentów danych.
Workery mają narzut: dodatkowe pliki, przekazywanie wiadomości i inny tryb debugowania. Pomiń je, gdy:
postMessage może zniwelować korzyści.Jeśli zadanie może spowodować zauważalne pauzy (często ~50ms+) i można je opisać jako „wejście → obliczenia → wyjście” bez dostępu do DOM, Web Worker zwykle jest tego wart. Jeśli to głównie aktualizacje UI, zostań na wątku głównym i optymalizuj tam.
A Service Worker to specjalny plik JavaScript działający w tle przeglądarki i pełniący rolę programowalnej warstwy sieciowej dla twojej strony. Zamiast działać na stronie, stoi między twoją aplikacją webową a siecią, pozwalając decydować, co się dzieje, gdy aplikacja żąda zasobów (HTML, CSS, API, obrazy).
Service Worker ma cykl życia oddzielony od pojedynczej karty:
Ponieważ może być zatrzymywany i uruchamiany ponownie w dowolnym momencie, traktuj go jak skrypt sterowany zdarzeniami: rób pracę szybko, zapisuj stan w trwałym magazynie i nie zakładaj, że będzie zawsze działający.
Service Workery są ograniczone do tego samego originu (ta sama domena/protokół/port) i kontrolują strony w obrębie swojego scope — zwykle folderu, z którego serwowany jest plik workera (i podkatalogów). Wymagają też HTTPS (poza localhost), ponieważ mogą wpływać na żądania sieciowe.
Service Worker służy głównie do stania między aplikacją a siecią. Może decydować, kiedy korzystać z sieci, kiedy z cache i kiedy wykonać pewne prace w tle — bez blokowania strony.
Najczęstsza rola to umożliwienie doświadczeń offline lub przy słabym połączeniu poprzez cache'owanie zasobów i odpowiedzi.
Kilka praktycznych strategii cache'owania:
To zwykle realizuje się za pomocą Cache Storage API i obsługi zdarzeń fetch.
Service Workery mogą poprawić postrzeganą szybkość przy powrotnych wizytach przez:
Efekt to mniej żądań sieciowych, szybsze uruchomienie i bardziej przewidywalna wydajność przy niestabilnym połączeniu.
Service Workery mogą zasilać funkcje w tle, takie jak powiadomienia push i background sync (wsparcie różni się w zależności od przeglądarki i platformy). Oznacza to, że możesz powiadamiać użytkowników lub ponownie próbować nieudanego żądania później — nawet jeśli strona nie jest otwarta.
Jeśli budujesz progressywną aplikację webową, Service Workery to kluczowy element odpowiedzialny za:
Jeśli zapamiętasz tylko jedną rzecz: Web Workery pomagają stronie wykonać ciężką pracę bez zamrażania UI, podczas gdy Service Workery pomagają aplikacji kontrolować żądania sieciowe i zachowywać się jak instalowalna aplikacja (PWA).
Web Worker służy do zadań obciążających CPU — parsowanie dużych danych, generowanie miniaturek, obliczenia — tak aby wątek główny pozostał responsywny.
Service Worker służy do obsługi żądań i zadań związanych z cyklem życia aplikacji — wsparcie offline, strategie cache, background sync i powiadomienia push. Może stać między aplikacją a siecią.
Web Worker zwykle jest przypięty do strony/karty. Gdy strona znika, worker zwykle też.
Service Worker jest sterowany zdarzeniami. Przeglądarka może go uruchomić, aby obsłużyć zdarzenie (np. fetch lub push), a potem zatrzymać, gdy będzie bezczynny — może więc działać nawet wtedy, gdy żadna karta nie jest otwarta.
Web Worker nie może przechwytywać żądań sieciowych robionych przez stronę. Może użyć fetch(), ale nie może przepisywać, cache'ować ani serwować odpowiedzi dla innych części twojej witryny.
Service Worker może przechwytywać żądania sieciowe (przez zdarzenie fetch) i decydować, czy iść do sieci, odpowiedzieć z cache, czy zwrócić fallback.
Web Worker nie zarządza cache HTTP twojej aplikacji.
Service Worker zazwyczaj używa Cache Storage API do przechowywania i serwowania par żądanie/odpowiedź — to podstawa dla cache offline i „natychmiastowych” powtórnych załadów.
Uruchomienie workera to głównie kwestia gdzie działa i jak jest ładowany. Web Workery tworzy się bezpośrednio z kodu strony. Service Workery rejestruje się, pozwalając przeglądarce zainstalować je i postawić „przed” żądaniami sieciowymi twojej witryny.
Web Worker powstaje, gdy strona go utworzy. Wskazujesz na osobny plik JS, a potem komunikujesz się przez postMessage.
// main.js (uruchamiany na stronie)
const worker = new Worker('/workers/resize-worker.js', { type: 'module' });
worker.postMessage({ action: 'start', payload: { /* ... */ } });
worker.onmessage = (event) => {
console.log('From worker:', event.data);
};
Dobry model mentalny: plik workera to po prostu kolejny URL skryptu, który strona może pobrać, ale on działa poza wątkiem głównym.
Service Workery muszą być zarejestrowane ze strony, którą odwiedza użytkownik:
// main.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
Po rejestracji przeglądarka zajmuje się cyklem install/activate. Twój sw.js może nasłuchiwać zdarzeń install, activate i fetch.
Service Workery mogą przechwytywać żądania i cache'ować odpowiedzi. Gdyby rejestracja była możliwa przez HTTP, atakujący mógłby wstrzyknąć złośliwy sw.js i przejąć kontrolę nad przyszłymi wizytami. HTTPS (lub http://localhost w środowisku deweloperskim) chroni skrypt i ruch, który może wpływać.
Przeglądarki cache'ują i aktualizują workery inaczej niż zwykłe skrypty strony. Plan aktualizacji:
sw.js/bundel).Jeśli chcesz płynniejszego wdrożenia, zobacz /blog/debugging-workers dla nawyków testowych, które wychwytują edge case'y aktualizacji wcześnie.
Workery zawodzą w inny sposób niż „zwykły” JavaScript strony: działają w oddzielnych kontekstach, mają własną konsolę i mogą być restartowane przez przeglądarkę. Solidny proces debugowania oszczędzi godziny.
Otwórz DevTools i poszukaj targetów specyficznych dla workerów. W Chrome/Edge często zobaczysz workery pod Sources (lub przez wpis „Dedicated worker”) i w selektorze kontekstu Konsoli.
Użyj tych samych narzędzi, co na wątku głównym:
onmessage i długotrwałe funkcje.Jeśli wiadomości „giną”, zbadaj obie strony: sprawdź, czy wywołujesz worker.postMessage(...), czy worker ma self.onmessage = ... i czy kształt wiadomości się zgadza.
Service Workery najlepiej debugować w panelu Application:
Również obserwuj Console w poszukiwaniu błędów install/activate/fetch — często wyjaśniają, dlaczego cache lub zachowanie offline nie działają.
Problemy z cache to największy pożeracz czasu: cache'owanie niewłaściwych plików (lub zbyt agresywne) może utrzymywać stary HTML/JS. Podczas testów wykonaj hard reload i potwierdź, co jest faktycznie serwowane z cache.
Dla realistycznych testów użyj DevTools, by:
Jeśli szybko iterujesz nad PWA, pomocne jest wygenerowanie czystej aplikacji bazowej (z przewidywalnym Service Workerem i outputem builda), a potem dopracowywanie strategii cache. Platformy takie jak Koder.ai mogą być przydatne do eksperymentów: możesz prototypować aplikację React z promptu, eksportować źródła i potem dopracowywać konfigurację workerów z szybszym feedbackiem.
Workery mogą uczynić aplikacje płynniejszymi i bardziej funkcjonalnymi, ale zmieniają miejsce wykonywania kodu i dostępne zasoby. Krótka lista zabezpieczeń, prywatności i wydajności zapobiegnie niespodziankom i niezadowolonym użytkownikom.
Zarówno Web Workery, jak i Service Workery są ograniczone przez zasadę tego samego pochodzenia: mogą bezpośrednio współdziałać tylko z zasobami z tego samego schematu/hosta/portu (chyba że serwer jawnie pozwala przez CORS). To zapobiega cichemu pobieraniu danych z innej witryny i mieszaniu ich w twojej aplikacji.
Service Workery mają dodatkowe zabezpieczenia: zazwyczaj wymagają HTTPS (albo localhost w dewelopmencie), bo przechwytywanie żądań to uprzywilejowana operacja. Traktuj je jak kod o podwyższonym zaufaniu: minimalizuj zależności, unikaj ładowania dynamicznego kodu i starannie wersjonuj logikę cache, aby stare cache nie serwowały przestarzałych plików.
Funkcje w tle powinny być przewidywalne. Powiadomienia push są potężne, ale prośby o zgodę łatwo nadużyć.
Proś o uprawnienia tylko wtedy, gdy jest jasna korzyść (np. po tym, jak użytkownik włączy powiadomienia w ustawieniach) i wyjaśnij, co otrzyma. Jeśli synchronizujesz lub prefetchujesz dane w tle, komunikuj to prostym językiem — użytkownicy zauważą nieoczekiwaną aktywność sieciową lub powiadomienia.
Workery nie są „darmową” wydajnością. Nadużywanie ich może się obrócić przeciwko tobie:
postMessage (szczególnie z dużymi obiektami) mogą stać się wąskim gardłem. Preferuj batchowanie i używanie transferables, gdy to możliwe.Nie każda przeglądarka wspiera każdą funkcję (lub użytkownicy mogą blokować uprawnienia). Wykrywaj funkcje i degraduj elegancko:
if ('serviceWorker' in navigator) {
// register service worker
} else {
// continue without offline features
}
Celem: podstawowa funkcjonalność powinna nadal działać, a „miłe do posiadania” funkcje (offline, push, ciężkie obliczenia) dodajesz, gdy są dostępne.
Web Workery i Service Workery rozwiązują różne problemy, więc dobrze ze sobą współpracują, gdy aplikacja potrzebuje zarówno intensywnych obliczeń, jak i szybkiego, niezawodnego ładowania. Dobry model: Web Worker = obliczenia, Service Worker = sieć + cache, wątek główny = UI.
Załóżmy, że twoja aplikacja pozwala edytować zdjęcia (skalowanie, filtry, usuwanie tła) i przeglądać galerię później bez połączenia.
To podejście „oblicz, potem zapisz” utrzymuje jasny podział obowiązków: worker produkuje wyniki, a service worker decyduje, jak je przechowywać i serwować.
Dla aplikacji z feedami, formularzami lub danymi polowymi:
Nawet bez pełnego background sync, service worker poprawia postrzeganą szybkość, serwując cache, podczas gdy aplikacja aktualizuje dane w tle.
Unikaj mieszania ról:
postMessage).Nie. Service Worker działa w tle, oddzielnie od kart, i nie ma bezpośredniego dostępu do DOM (elementów HTML strony).
To odizolowanie jest celowe: Service Worker ma działać nawet wtedy, gdy nie ma aktywnego dokumentu (np. żeby odpowiedzieć na zdarzenie push lub serwować zasoby z cache). Jeśli Service Worker musi wpłynąć na to, co widzi użytkownik, komunikuje się ze stronami przez messaging (np. postMessage), aby strona mogła zaktualizować UI.
Nie. Web Workery i Service Workery są niezależne.
Możesz używać jednego bez drugiego lub obu, jeśli aplikacja tego wymaga.
W nowoczesnych przeglądarkach Web Workery są szeroko wspierane i zwykle stanowią bezpieczny punkt wyjścia.
Service Workery też są powszechnie wspierane w aktualnych wersjach głównych przeglądarek, ale mają więcej wymagań i edge case'ów:
localhost w dewelopmencie).Jeśli zależy ci na szerokiej kompatybilności, traktuj funkcje Service Workera jako progresywne ulepszenie: najpierw zbuduj solidne rdzeń, potem dodawaj offline/push tam, gdzie to dostępne.
Nie automatycznie.
Rzeczywiste korzyści pochodzą z zastosowania właściwego workera do właściwego wąskiego gardła i mierzenia rezultatów przed i po.
Użyj Web Workera, gdy masz prace obciążające CPU, które można opisać jako wejście → obliczenia → wynik i które nie potrzebują dostępu do DOM.
Dobre zastosowania: parsowanie/transformacja dużych ładunków, kompresja, kryptografia, przetwarzanie obrazów/dźwięku oraz złożone filtrowanie. Jeśli zadanie to głównie aktualizacje UI lub częste odczyty/zapisy DOM, worker nie pomoże (i tak nie ma dostępu do DOM).
Użyj Service Workera, gdy potrzebujesz kontroli nad siecią: wsparcia offline, strategii cache, szybszych powrotów użytkownika, routingu żądań oraz (gdzie dostępne) push/background sync.
Jeśli problem to „UI zamiera podczas obliczeń”, to zadanie dla Web Workera. Jeśli problem to „ładowanie jest wolne / offline nie działa”, to zadanie dla Service Workera.
Nie. Web Workery i Service Workery są niezależne.
Możesz używać każdego z nich osobno albo obu jednocześnie, gdy potrzebujesz zarówno obliczeń, jak i funkcji sieciowych/offline.
Głównie zakres i czas życia.
fetch) nawet wtedy, gdy żadna karta nie jest otwarta, a potem wyłączyć się, gdy stanie się bezczynny.Nie. Web Workery nie mają dostępu do window/document.
Jeśli musisz zmienić UI, wyślij dane z powrotem do głównego wątku przez postMessage(), a tam zaktualizuj DOM. Worker powinien skupiać się na czystych obliczeniach.
Nie. Service Workery nie mają dostępu do DOM.
Aby wpłynąć na to, co widzi użytkownik, komunikuj się z kontrolowanymi stronami przez messaging (np. Clients API + postMessage()), i pozwól stronie zaktualizować UI.
Używaj postMessage() po obu stronach.
worker.postMessage(data)self.postMessage(result)Dla dużych danych binarnych preferuj transferables (np. ArrayBuffer), by uniknąć kopiowania:
Service Workery stoją między aplikacją a siecią i mogą odpowiadać na żądania przy użyciu Cache Storage API.
Typowe strategie:
Wybieraj strategię dla typu zasobu (app shell vs dane API), a nie jedną regułę globalną.
Tak, ale trzymaj odpowiedzialności oddzielnie.
Typowy wzorzec:
To zapobiega mieszaniu logiki i utrzymuje wydajność przewidywalną.
Użyj właściwego widoku DevTools dla każdego typu.
onmessage i profiluj, by potwierdzić, że główny wątek pozostaje responsywny.Przy błędach cache zawsze zweryfikuj, co faktycznie jest serwowane (sieć vs cache) i testuj tryby offline/throttling.
worker.postMessage(buffer, [buffer]);