JavaScript Web Workers: een Beginner's Guide
In 2019 is het webecosysteem zodanig geëvolueerd dat de browser een uitvoeringsomgeving is voor toepassingen die op JavaScript zijn gebouwd. Dit wordt weerspiegeld in de snelheid waarmee de industrie komt met nieuwe frameworks, paradigma ‘ s, module laders en bundlers, afhankelijkheid managers, build tools, en pakket managers jaar na jaar.
toen JavaScript werd bedacht in de begindagen van het internet, was de richting van internetontwikkeling niet duidelijk. Als gevolg van de constante, snelle verandering in de industrie en het ecosysteem, de behoefte aan de achterwaartse compatibiliteit van browsers en webstandaarden, de evolutie van JavaScript werd een constante stroom van patches, hacks en achteraf.
de huidige mobiele apparaten worden normaal gesproken geleverd met 8+ CPU-cores, of 12+ GPU-cores. Desktop en server CPU ‘ s hebben tot 16 cores, 32 threads, of meer.
in deze omgeving is het hebben van een dominante programmeer-of scripting-omgeving met één threaded een knelpunt.
JavaScript Is Single-threaded
Dit betekent dat door het ontwerp, JavaScript-engines-oorspronkelijk browsers-hebben een hoofd thread van de uitvoering, en, om het simpel te zeggen, proces of functie B kan niet worden uitgevoerd totdat proces of functie A is voltooid. De gebruikersinterface van een webpagina reageert niet op een andere JavaScript-verwerking terwijl het bezig is met het uitvoeren van iets-Dit staat bekend als DOM-blokkering.
Dit is vreselijk inefficiënt, vooral in vergelijking met andere talen.
als we naar JS Bin gaan en deze code uitvoeren in de JavaScript console van de browser:
//noprotecti = 0;while (i < 60000) { console.log("The number is " + i); i++;}
… het geheel jsbin.com website reageert niet totdat de browser telt — en logs-tot 60.000.
we zullen niet in staat zijn om te communiceren met iets op de pagina, omdat de browser bezet is.
Dit is een relatief weinig veeleisend computerproces, en de huidige web apps hebben vaak veel meer veeleisende taken.
We moeten dingen op de achtergrond kunnen berekenen terwijl de gebruiker naadloos samenwerkt met de pagina.
Web Workers
het W3C publiceerde een eerste ontwerp van de web workers standard in 2009. De volledige specificatie kan worden gevonden op de web Hypertext Application Technology Working Group website — of WHATWG — een web standards body alternatief voor W3C.
Web workers is een asynchrone systeem, of protocol, voor webpagina ‘ s om taken uit te voeren op de achtergrond, onafhankelijk van de hoofdthread en website UI. Het is een geïsoleerde omgeving die is geïsoleerd van hetwindow
object, het document
object, directe internettoegang en het meest geschikt is voor langdurige of veeleisende computationele taken.
afgezien van web workers-een systeem gewijd aan multithreading-zijn er andere manieren om asnychrone verwerking in JavaScript te bereiken, zoals asynchrone Ajax aanroepen, en event loop.
om dit aan te tonen, gaan we terug naar JS Bin en proberen we dit fragment:
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);
wanneer we dit uitvoeren, is onze logvolgorde A, C, E, D, F, B
. De browser plant eerst bewerkingen zonder de time-out, zoals ze komen, en voert vervolgens de setTimeout()
functies uit in de volgorde van hun respectievelijke opgegeven vertragingen. Deze asynchroniciteit mag echter niet automatisch worden verward met multithreading. Afhankelijk van de host machine, kan dit vaak slechts een single-thread stack van de gesprekken in de volgorde die we uitgelegd.
Web Workers & Multithreading
zoals Mozilla ’s JavaScript-referentiewebsite uitlegt, zijn web workers een” middel voor web content om scripts in achtergrond threads uit te voeren.”
we gebruiken ze op de volgende manier: we controleren op de beschikbaarheid van de Worker()
constructor in de browser, en als deze beschikbaar is, installeren we een werkobject, met de URL van het script als argument. Dit script wordt uitgevoerd op een aparte thread.
het script moet vanuit dezelfde host of domein worden geserveerd om veiligheidsredenen, en dat is ook de reden dat web workers niet zullen werken als we het bestand lokaal Openen met een file://
schema.
if (typeof(Worker) !== "undefined") { worker = new Worker("worker.js");}
nu definiëren we deze code in het worker.js
bestand:
i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}
Als u hoogwaardige JavaScript-webwerkbestanden wilt schrijven, bekijk dan ons boek, JavaScript: Best Practice.
de scheiding van Threads
een belangrijk ding om hier op te merken is de scheiding van de window
en document
scope van uitvoering in het hoofdbrowservenster thread, en de worker
scope.
om gebruik te kunnen maken van de worker
thread, moeten deze twee scopes kunnen communiceren. Om dit te bereiken gebruiken we de postMessage()
functie binnen de worker.js
bestand — om berichten naar de hoofdbrowser thread te sturen — en de worker.onmessage
luisteraar in de hoofdthread om naar worker
berichten te luisteren.
We kunnen ook berichten verzenden van de hoofdbrowser thread naar de worker
thread of functie. Het enige verschil is dat we dingen omkeren, en worker.postMessage()
aanroepen op de hoofdthread, en onmessage
op de werkthread. Om Mozilla ‘ s developer reference te citeren:
merk op dat
onmessage
enpostMessage()
moeten worden opgehangen aan hetWorker
object wanneer gebruikt in de hoofdscript thread, maar niet wanneer gebruikt in de werkmachine. Dit komt omdat, binnen de werknemer, de werknemer is effectief de wereldwijde scope.
we kunnen de terminate()
methode op dezelfde manier gebruiken om de uitvoering van onze werknemer te beëindigen.
met dit alles in gedachten komen we bij dit voorbeeld:
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>
en werknemer.js:
i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}
Dit geeft ons de mogelijkheid om de effecten van main-thread uitvoering op het gedrag en de prestaties van pagina ‘ s te testen ten opzichte van de effecten van de webwerker.
in deze tutorial hebben we http-server
gebruikt om de bestanden lokaal aan te bieden.
nu kunnen we zien dat de werk thread de interactiviteit van het hoofdbrowserproces niet blokkeert, en dat looping door 200.000 nummers geen invloed heeft op de hoofdthread. De getallen in het#workerOutput
element worden bij elke iteratie bijgewerkt.
de blokkerende thread, of hoofd thread, blokkeert alle interactiviteit (we hebben het aantal iteraties hier op 200.000 gezet, maar het zal nog duidelijker zijn als we het verhogen naar 2.000.000).
nog een ding dat ons naar een geblokkeerde hoofdthread wijst is dat het werkproces de pagina bij elke iteratie bijwerkt, en de lus in de hoofdthread (die gedefinieerd is in index.html
) alleen het #mainThreadOutput
element bij de laatste iteratie bijwerkt.
Dit komt omdat de browser te veel bezig is met tellen (for
loop) om de DOM te kunnen hertekenen, dus het doet het pas als zijn bedrijf met de for
loop volledig klaar is (aan het einde van de loop).
conclusie
In dit artikel introduceerden we web workers, een technologie die de webindustrie helpt om steeds veeleisender webapps bij te houden. Dit wordt gedaan door het verstrekken van een manier voor web apps om multi-processor en multi-threaded apparaten te benutten door het toekennen van een aantal multi-threaded superkrachten aan JavaScript.
Webwerkers maken van de mobiele en desktop browser omgevingen applicatieplatforms, waardoor ze een strikte uitvoeringsomgeving hebben. Deze strengheid kan ons dwingen om te zorgen voor het kopiëren van objecten tussen meerdere threads, en om onze toepassingen te plannen met deze beperkingen in het achterhoofd.