JavaScript Web Workers: początkujący's Guide
w 2019 roku ekosystem internetowy ewoluował do tego stopnia, że przeglądarka jest środowiskiem wykonawczym dla aplikacji zbudowanych w oparciu o JavaScript. Znajduje to odzwierciedlenie w szybkości, z jaką branża opracowuje nowe ramy, paradygmaty, Moduły ładujące i pakiety, Menedżery zależności, narzędzia do budowania i Menedżery pakietów rok po roku.
Kiedy JavaScript powstawał w początkach Internetu, kierunek rozwoju Internetu nie był jasny. Ze względu na ciągłe, szybkie zmiany w branży i ekosystemie, potrzebę wstecznej kompatybilności przeglądarek i standardów internetowych, ewolucja JavaScript stała się stałym strumieniem łatek, hacków i przemyśleń.
dzisiejsze urządzenia mobilne zwykle mają 8+ Rdzeni PROCESORA lub 12+ rdzeni GPU. Procesory pulpitu i serwera mają do 16 rdzeni, 32 wątki lub więcej.
w tym środowisku dominujące środowisko programistyczne lub Skryptowe, które jest jednowątkowe, jest wąskim gardłem.
JavaScript jest jednowątkowy
oznacza to, że z założenia silniki JavaScript-pierwotnie przeglądarki — mają jeden główny wątek wykonania, a mówiąc prościej, proces lub funkcja B nie mogą być wykonane, dopóki proces lub funkcja a nie zostaną zakończone. Interfejs strony internetowej nie reaguje na żadne inne przetwarzanie JavaScript podczas wykonywania czegoś-jest to znane jako blokowanie DOM.
jest to strasznie nieefektywne, szczególnie w porównaniu z innymi językami.
jeśli przejdziemy do js Bin i uruchomimy ten kod w konsoli JavaScript przeglądarki:
//noprotecti = 0;while (i < 60000) { console.log("The number is " + i); i++;}
… cały jsbin.com witryna przestanie odpowiadać, dopóki przeglądarka nie zliczy i nie zaloguje się do 60 000.
nie będziemy mogli wchodzić w interakcje z niczym na stronie, ponieważ przeglądarka jest zajęta.
jest to stosunkowo mało wymagający proces obliczeniowy, a dzisiejsze aplikacje internetowe często wymagają znacznie bardziej wymagających zadań.
musimy być w stanie obliczyć rzeczy w tle, podczas gdy użytkownik bezproblemowo wchodzi w interakcję ze stroną.
Web Workers
W3C opublikowało pierwszy projekt standardu web workers w 2009 roku. Pełną specyfikację można znaleźć na stronie web Hypertext Application Technology Working Group – lub WHATWG-web standards body alternatywą dla W3C.
Web workers to Asynchroniczny system lub protokół dla stron internetowych do wykonywania zadań w tle, niezależnie od głównego wątku i interfejsu strony internetowej. Jest to izolowane środowisko, które jest izolowane od obiektuwindow
, obiektudocument
, bezpośredniego dostępu do Internetu i najlepiej nadaje się do długotrwałych lub wymagających zadań obliczeniowych.
oprócz Web workerów — systemu dedykowanego do wielowątkowości — istnieją inne sposoby osiągnięcia asnychronous przetwarzania w JavaScript, takie jak asynchroniczne wywołania Ajax i pętla zdarzeń.
aby to zademonstrować, wrócimy do js Bin i spróbujemy tego fragmentu:
console.log("A");setTimeout(function(){console.log("B");},2000);console.log("C");setTimeout(function(){console.log("D");},0);console.log("E");setTimeout(function(){console.log("F");},1000);
Kiedy to uruchomimy, nasza Sekwencja logów to A, C, E, D, F, B
. Przeglądarka najpierw zaplanuje operacje bez limitu czasu, w miarę ich pojawiania się, a następnie wykona funkcje setTimeout()
w kolejności ich odpowiednich określonych opóźnień. Jednak ta asynchroniczność nie powinna być automatycznie łączona z wielowątkowością. W zależności od komputera hosta, często może to być tylko jednowątkowy stos wywołań w kolejności, którą wyjaśniliśmy.
pracownicy sieci Web& wielowątkowość
jak wyjaśnia strona internetowa referencyjna JavaScript Mozilli, pracownicy sieci Web są „środkiem do uruchamiania skryptów w wątkach w tle.”
używamy ich w następujący sposób: sprawdzamy dostępność konstruktoraWorker()
w przeglądarce, a jeśli jest dostępny, tworzymy instancję obiektu worker, z adresem URL skryptu jako argumentem. Skrypt ten zostanie wykonany w osobnym wątku.
skrypt musi być obsługiwany z tego samego hosta lub domeny ze względów bezpieczeństwa, i to jest również powód, dla którego pracownicy sieci nie będą działać, jeśli otworzymy plik lokalnie za pomocą schematufile://
.
if (typeof(Worker) !== "undefined") { worker = new Worker("worker.js");}
teraz definiujemy ten kod w pliku worker.js
:
i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}
Jeśli chcesz napisać wysokiej jakości pliki JavaScript web worker, sprawdź naszą książkę, JavaScript: Best Practice.
rozdzielenie wątków
ważną rzeczą do odnotowania jest rozdzielenie zakresuwindow
Idocument
w głównym wątku okna przeglądarki oraz zakresuworker
.
aby skorzystać z wątkuworker
, te dwa zakresy muszą być w stanie się komunikować. Aby to osiągnąć, używamy funkcji postMessage()
w pliku worker.js
— do wysyłania wiadomości do głównego wątku przeglądarki — i worker.onmessage
słuchacza w głównym wątku do słuchania wiadomości worker
.
możemy również wysyłać wiadomości z głównego wątku przeglądarki do worker
wątku lub funkcji. Jedyną różnicą jest to, że odwracamy rzeczy i wywołujemy worker.postMessage()
w wątku głównym i onmessage
w wątku roboczym. Cytując referencje programistów Mozilli:
zauważ, że
onmessage
IpostMessage()
muszą być zawieszone naWorker
Obiekt, gdy jest używany w głównym wątku skryptu, ale nie gdy jest używany w workerze. Dzieje się tak dlatego, że wewnątrz pracownika pracownik jest w rzeczywistości globalnym zakresem.
możemy użyć metodyterminate()
w ten sam sposób, aby zakończyć wykonywanie naszego workera.
Mając to wszystko na uwadze, dochodzimy do tego przykładu:
index.html
<!DOCTYPE html><html><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>Web Workers Example</title> <style type="text/css"> body {padding-top:28px;} .output-cont {margin-left:12%; margin-top:28px;} .output-cont h3 {width:200px; height:100%;} .output-cont button {padding:4px 8px; font-size:1.1rem; font-family:sans-serif; } </style></head><body><div class="output-cont"><button onclick="testWorker()">start worker</button><h3></h3><button onclick="terminateWorker()">terminate worker</button></div><br/><div class="output-cont"><button onclick="testMainThread()">start blocking thread</button><h3></h3></div><br/><div class="output-cont"><button onclick="alert('browser responsive!')">test browser responsiveness</button></div> <script> var worker; function testWorker() { if (typeof(Worker) !== "undefined") { if (typeof(worker) == "undefined") { worker = new Worker("worker.js"); } worker.onmessage = function(event) { document.getElementById("workerOutput").innerHTML = event.data; }; } else { document.getElementById("workerOutput").innerHTML = "Web Workers are not supported in your browser"; } } function terminateWorker() { worker.terminate(); worker = undefined; } function testMainThread() { for (var i = 0; i < 200000; i++) { document.getElementById("mainThreadOutput").innerHTML = "Main Thread Counter: " + i; } } </script></body></html>
i worker.js:
i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}
daje nam to możliwość przetestowania wpływu wykonania głównego wątku na zachowanie i wydajność strony w porównaniu z efektami Web workera.
w tym samouczku użyliśmy http-server
do serwowania plików lokalnie.
teraz widzimy, że wątek roboczy nie blokuje interaktywności głównego procesu przeglądarki, a zapętlenie przez 200 000 liczb nie wpływa na główny wątek. Liczby w elemencie#workerOutput
są aktualizowane przy każdej iteracji.
wątek blokujący, lub główny wątek, gdy jest zaangażowany w pętlę, blokuje całą interaktywność (ustawiliśmy tutaj liczbę iteracji na 200 000, ale będzie to jeszcze bardziej oczywiste, jeśli zwiększymy go do 2 000 000).
jeszcze jedną rzeczą, która wskazuje nam na zablokowany główny wątek jest to, że proces roboczy aktualizuje stronę przy każdej iteracji, a pętla w głównym wątku (ta zdefiniowana windex.html
) aktualizuje tylko element#mainThreadOutput
przy ostatniej iteracji.
dzieje się tak dlatego, że przeglądarka jest zbyt pochłonięta z liczeniem (for
pętla), aby móc ponownie narysować DOM, więc robi to tylko wtedy, gdy jej działalność zfor
pętla jest w pełni wykonana (na końcu pętli).
podsumowanie
w tym artykule przedstawiliśmy Web workers, technologię, która pomaga branży internetowej nadążyć za coraz bardziej wymagającymi aplikacjami internetowymi. Odbywa się to poprzez zapewnienie aplikacji internetowych sposobu na wykorzystanie wieloprocesorowych i wielowątkowych urządzeń poprzez nadanie kilku wielowątkowych supermocy JavaScript.
pracownicy sieci przekształcają środowiska przeglądarek mobilnych i desktopowych w platformy aplikacji, zapewniając im ścisłe środowisko wykonawcze. Ta ścisłość może zmusić nas do zapewnienia kopiowania obiektów między wieloma wątkami i planowania naszych aplikacji z uwzględnieniem tych ograniczeń.