Heeft u ooit code in de browser moeten uitvoeren die zo lang duurde voordat uw toepassing een tijdje niet meer reageerde? Met HTML5-webwerkers hoeft u dat nooit meer te ervaren.
Met webwerkers kunt u langlopende code scheiden en onafhankelijk uitvoeren van andere code die op de pagina wordt uitgevoerd. Hierdoor blijft uw gebruikersinterface responsief, zelfs tijdens complexe bewerkingen.
Wat zijn webwerkers?
Traditioneel is JavaScript een taal met één thread. Dat betekent dat niets anders kan worden uitgevoerd terwijl één stukje code wordt uitgevoerd. Als u bijvoorbeeld code hebt die probeert een DOM-element te animeren, moet code die een variabele probeert te wijzigen, wachten tot de animatie is afgelopen voordat deze kan worden uitgevoerd.
Webworkers zijn JavaScript-bestanden die in een aparte thread worden uitgevoerd zonder directe toegang tot de DOM.
Een manier om aan webwerkers te denken, is dat het stukjes code zijn die veel tijd nodig hebben om uit te voeren, dus je geeft ze aan de browser om ze op de achtergrond uit te voeren. Aangezien die code nu op de achtergrond wordt uitgevoerd, heeft dit geen invloed op het JavaScript dat verantwoordelijk is voor uw webpagina.
Als bijwerking kan het niet langer rechtstreeks communiceren met de rest van uw code, dus webwerkers hebben geen toegang tot de DOM. Er zijn echter nog veel andere browser-API's beschikbaar, waaronder de WebSocket- en Fetch-API's.
Webwerkers zijn echter niet helemaal geïsoleerd van de rode draad. Wanneer een werknemer moet communiceren met de hoofdthread, kan deze een bericht verzenden en kan de hoofdthread zijn eigen bericht verzenden als reactie.
Waarom webwerkers?
Vóór webwerkers was de enige manier om JavaScript uit te voeren waarvoor veel tijd in de browser nodig was:
- Accepteer dat de pagina een tijdje niet meer reageert.
- Breek die code in asynchrone brokken.
Aangezien een niet-reagerende pagina meestal een slechte gebruikerservaring is, kunt u kiezen voor de asynchrone optie. Op deze manier code schrijven betekent het in kleinere stukjes verdelen die de browser kan uitvoeren terwijl deze de gebruikersinterface niet afhandelt. De stukjes moeten zo klein zijn dat als de gebruikersinterface moet worden bijgewerkt, de browser het huidige stuk kan uitvoeren en de gebruikersinterface kan verzorgen.
Webworkers zijn aan HTML5 toegevoegd om een betere oplossing voor dit probleem te bieden. In plaats van je te dwingen creatief te zijn met asynchrone code, laten ze je een functie netjes scheiden om in zijn eigen geïsoleerde thread te draaien.
Dit maakte het voor ontwikkelaars gemakkelijker om dergelijke code te schrijven en verbeterde ook de gebruikerservaring.
Gebruiksscenario's voor webwerkers
Elke toepassing die veel rekenwerk vereist aan de kant van de klant, kan baat hebben bij webwerkers.
Stel dat uw toepassing bijvoorbeeld een gebruiksrapport wil genereren en alle gegevens op de client opslaat uit privacyoverwegingen.
Om dat rapport te genereren, moet uw webtoepassing de gegevens ophalen, er berekeningen op uitvoeren, de resultaten ordenen en aan de gebruiker presenteren.
Als je dat in de hoofdthread zou proberen, zou de gebruiker de applicatie volledig niet kunnen gebruiken terwijl de applicatie de gegevens verwerkt. In plaats daarvan kunt u een deel van of alle code naar een webwerker verplaatsen. Hierdoor kan de gebruiker de applicatie blijven gebruiken terwijl de berekeningen worden uitgevoerd.
Hoe webwerkers in JavaScript te gebruiken
De Web Worker-API definieert hoe webwerkers moeten worden gebruikt. Het gebruik van deze API omvat het maken van een Worker-object met de Worker-constructor als volgt:
laat newWorker = Worker('werknemer.js');
De arbeider constructor accepteert de naam van een JavaScript-bestand als parameter en voert het bestand uit in een nieuwe thread. Het retourneert een Worker-object zodat de hoofdthread kan communiceren met de worker-thread.
Werknemers communiceren met de rode draad door berichten heen en weer te sturen. Je gebruikt de postBericht functie om gebeurtenissen tussen de worker en de hoofdthread te verzenden. Gebruik de onbericht gebeurtenislistener om te luisteren naar berichten van de andere partij.
Hier is een codevoorbeeld. Ten eerste kan een hoofdthread er als volgt uitzien:
laten arbeider = nieuwe Werknemer('werknemer.js')
werknemer.postMessage('Hoi!')
worker.onmessage = functie(e) {
console.log('Werkthread zegt:', e.data)
}
Deze hoofdthread maakt een worker-object van worker.js en stuurt er vervolgens een bericht naar met worker.postMessage. Het definieert dan een gebeurtenislistener, vergelijkbaar in concept met a DOM-gebeurtenislistener. Elke keer dat de werknemer een bericht terugstuurt naar de hoofdthread, wordt een gebeurtenis geactiveerd en de handler registreert het bericht van de werknemer in de console.
De code in de worker (worker.js) heeft één taak:
onmessage = functie(e) {
laten bericht = e.data;
console.log('Hoofddraad zei:', bericht);
postBericht('Hoi!')
}
Het luistert naar berichten die vanuit de hoofdthread zijn verzonden, logt het bericht in de console en stuurt een retourbericht terug naar de hoofdthread.
De berichten in dit voorbeeld zijn allemaal strings geweest, maar dat is geen vereiste: je kunt bijna elk type gegevens als bericht verzenden.
Het soort werkers dat je tot nu toe hebt gezien, worden toegewijde werkers genoemd. Je hebt er alleen toegang toe vanuit het bestand waarin je ze hebt gemaakt (ze zijn eraan gewijd). Gedeelde werknemers zijn het tegenovergestelde: ze kunnen berichten ontvangen van en berichten verzenden naar meerdere bestanden. Gedeelde werknemers zijn conceptueel hetzelfde als toegewijde werknemers, maar u moet ze een beetje anders gebruiken.
Laten we naar een voorbeeld kijken. In plaats van de Worker-constructor te gebruiken, moet elk bestand dat een gedeelde worker wil gebruiken een worker-object maken met SharedWorker():
laten sharedWorker = nieuwe SharedWorker('worker.js')
De verschillen houden daar echter niet op. Om een bestand een bericht van een gedeelde werknemer te laten verzenden of ontvangen, moet het dit doen door toegang te krijgen tot een haven object, in plaats van dit direct te doen. Hier is hoe dat eruit ziet:
sharedWorker.port.postMessage('Hallo daar!')
sharedWorker.port.onMessage = functie(e) {
console.log('De gedeelde werknemer heeft verzonden', e.gegevens);
}
U moet ook het port-object in de worker gebruiken:
onconnect = functie(e) {
const poort = e.poorten[0];
poort.onmessage = functie(e) {
console.log('Bericht ontvangen', e.data)
port.postMessage('Hallo!');
}
}
De onconnect luisteraar vuurt elke keer dat er een verbinding met een poort plaatsvindt (wanneer een onbericht gebeurtenislistener is ingesteld in de hoofdthread).
Wanneer dat gebeurt, haalt de code de poort waarmee zojuist is verbonden uit de connect-gebeurtenis en slaat deze op in een variabele. Vervolgens registreert de code de onbericht luisteraar op het poortobject. De code logt vervolgens het bericht in de console en gebruikt de poort om een bericht terug te sturen naar de hoofdthread.
Webwerkers verbeteren de gebruikerservaring
Webworkers zijn JavaScript-threads waarmee u complexe en langlopende stukjes code op de achtergrond kunt uitvoeren. Deze code zal dan voorkomen dat de gebruikersinterface wordt geblokkeerd. Het gebruik van webworkers maakt het schrijven van dit soort code veel gemakkelijker en verbetert de ervaring voor de gebruiker van de applicatie. U kunt webworkers maken en ermee communiceren met behulp van de webworker-API.