Articles

javascript web Workers: a Beginner's Guide

în 2019, ecosistemul web a evoluat până la punctul în care browserul este un mediu de execuție pentru aplicații construite pe JavaScript. Acest lucru se reflectă în viteza cu care industria vine cu noi cadre, paradigme, Încărcătoare de module și pachete, manageri de dependență, instrumente de construire și manageri de pachete an de an.

când JavaScript a fost conceput în primele zile ale Internetului, direcția de dezvoltare a internetului nu era clară. Datorită schimbării constante și rapide a industriei și a ecosistemului, necesitatea compatibilității înapoi a browserelor și a standardelor web, evoluția JavaScript a devenit un flux constant de patch-uri, hacks și afterthoughts.

JavaScript web workers load

dispozitivele mobile de astăzi vin în mod normal cu 8+ nuclee CPU sau 12+ nuclee GPU. Procesoarele Desktop și server au până la 16 nuclee, 32 de fire sau mai multe.

în acest mediu, a avea un mediu dominant de programare sau scripting care este cu un singur fir este un blocaj.

JavaScript este cu un singur fir

aceasta înseamnă că, prin proiectare, motoarele JavaScript-inițial browserele — au un fir principal de execuție și, pur și simplu, procesul sau funcția B nu pot fi executate până când procesul sau funcția A nu este terminată. Interfața de utilizare a unei pagini web nu răspunde la nicio altă procesare JavaScript în timp ce este ocupată cu executarea a ceva — acest lucru este cunoscut sub numele de blocare DOM.

Acest lucru este teribil de ineficient, mai ales în comparație cu alte limbi.

dacă mergem la JS Bin și rulăm acest cod în consola JavaScript a browserului:

//noprotecti = 0;while (i < 60000) { console.log("The number is " + i); i++;}

… întregul jsbin.com site — ul web nu va răspunde până când browserul contează — și se înregistrează-la 60.000.

nu vom putea interacționa cu nimic din pagină, deoarece browserul este ocupat.

acum, acesta este un proces de calcul relativ nedemontabil, iar aplicațiile web de astăzi implică adesea sarcini mult mai solicitante.

trebuie să putem calcula lucrurile în fundal în timp ce utilizatorul interacționează perfect cu pagina.

Web Workers

W3C a publicat un prim proiect al standardului web workers în 2009. Specificația completă poate fi găsită pe site — ul web Hypertext Application Technology Working Group — sau WHATWG-o alternativă a corpului standardelor web la W3C.

Web workers este un sistem asincron sau protocol pentru ca paginile web să execute sarcini în fundal, independent de firul principal și interfața site-ului web. Este un mediu izolat care este izolat de obiectul window, obiectuldocument, acces direct la internet și este cel mai potrivit pentru sarcini de calcul de lungă durată sau solicitante.

În afară de lucrătorii web — un sistem dedicat multithreading — există și alte modalități de a realiza procesarea asnychronous în JavaScript, cum ar fi apelurile asincrone Ajax și bucla de evenimente.

pentru a demonstra acest lucru, vom reveni la JS Bin și vom încerca acest 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);

când rulăm acest lucru, secvența noastră de jurnal este A, C, E, D, F, B. Browserul programează mai întâi operațiunile fără timeout, pe măsură ce vin, apoi execută funcțiile setTimeout() în ordinea întârzierilor specificate. Cu toate acestea, această asincronitate nu ar trebui să fie combinată automat cu multithreading. În funcție de mașina gazdă, aceasta poate fi adesea doar o stivă cu un singur fir a apelurilor în ordinea pe care am explicat-o.

Web Workers& Multithreading

după cum explică site-ul de referință JavaScript Mozilla, web workers sunt un „mijloc pentru conținutul web pentru a rula scripturi în fire de fundal.”

le folosim în felul următor: verificăm disponibilitateaWorker() constructor în browser și, dacă este disponibil, instanțiem un obiect worker, cu URL-ul scriptului ca argument. Acest script va fi executat pe un fir separat.

scriptul trebuie servit din aceeași gazdă sau domeniu din motive de securitate și acesta este și motivul pentru care lucrătorii web nu vor funcționa dacă deschidem fișierul local cu o schemăfile://.

if (typeof(Worker) !== "undefined") { worker = new Worker("worker.js");} 

acum definim acest cod în fișierulworker.js :

i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}

Dacă doriți să scrieți fișiere JavaScript web worker de înaltă calitate, consultați cartea noastră, JavaScript: Best Practice.

separarea firelor

Un lucru important de reținut aici este separareawindow șidocument domeniul de execuție în firul ferestrei principale a browserului șiworker domeniul de aplicare.

pentru a face uz deworker fir, aceste două domenii trebuie să fie în măsură să comunice. Pentru a realiza acest lucru, folosim postMessage() funcția din worker.js fișier — pentru a trimite mesaje către firul principal al browserului — și worker.onmessage ascultător în firul principal pentru a asculta worker mesaje.

de asemenea, putem trimite mesaje din firul principal al browserului către firul sau funcțiaworker. Singura diferență este că inversăm lucrurile și apelăm worker.postMessage() pe firul principal și onmessage pe firul lucrătorului. Pentru a cita referința dezvoltatorului Mozilla:

observați căonmessage șipostMessage() trebuie să fie agățate deWorker obiect atunci când este utilizat în firul script principal, dar nu atunci când este utilizat în lucrător. Acest lucru se datorează faptului că, în interiorul lucrătorului, lucrătorul este efectiv domeniul de aplicare global.

putem folosi metodaterminate() în același mod, pentru a încheia execuția lucrătorului nostru.

având în vedere toate acestea, ajungem la acest exemplu:

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 lucrător.js:

i = 0;while (i < 200000) { postMessage("Web Worker Counter: " + i); i++;}

Acest lucru ne oferă posibilitatea de a testa efectele execuției firului principal asupra comportamentului și performanței paginii față de efectele lucrătorului web.

în acest tutorial, am folosithttp-server pentru a servi fișierele la nivel local.

javascript web workers testarea

acum putem vedea că firul lucrător nu blochează interactivitatea procesului browser-ul principal, și looping prin 200.000 de numere nu afectează firul principal. Numerele din elementul #workerOutput sunt actualizate la fiecare iterație.

firul de blocare, sau firul principal, atunci când este angajat într-o buclă, blochează toată interactivitatea (am setat numărul de iterații la 200.000 aici, dar va fi și mai evident dacă îl creștem la 2.000.000).

încă un lucru care ne indică un fir principal blocat este că procesul de lucru actualizează pagina la fiecare iterație, iar bucla din firul principal (cea definită în index.html) actualizează doar elementul #mainThreadOutput din ultima iterație.

Acest lucru se datorează faptului că browserul este prea consumat cu numărarea (for buclă) pentru a putea redesena DOM, așa că o face doar o singură dată afacerea sa cufor bucla este complet terminată (la sfârșitul buclei).

concluzie

în acest articol, am introdus web workers, o tehnologie care ajută industria web să țină pasul cu aplicațiile web din ce în ce mai solicitante. Acest lucru se face prin furnizarea unei modalități pentru aplicațiile web de a utiliza dispozitive multi-procesor și multi-threaded prin acordarea unor superputeri multi-threaded JavaScript.

lucrătorii web transformă mediile browserului mobil și desktop în platforme de aplicații, oferindu-le un mediu strict de execuție. Această strictețe ne poate forța să asigurăm copierea obiectelor între mai multe fire și să ne planificăm aplicațiile având în vedere aceste constrângeri.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *