Articles

Trådning af nettet med modularbejdere

JavaScript er single-threaded, hvilket betyder, at det kun kan udføre en operation ad gangen. Dette er intuitivt og fungerer godt i mange tilfælde på nettet, men kan blive problematisk, når vi skal udføre tunge løfteopgaver som databehandling, parsing, beregning eller analyse. Efterhånden som flere og mere komplekse applikationer leveres på nettet, er der et øget behov for multi-threaded behandling.

på internetplatformen er den vigtigste primitive for trådning og parallelisme INTERNETARBEJDERNES API. Arbejdere er en let abstraktion oven på operativsystemtråde, der udsætter en besked, der passerer API til kommunikation mellem tråde. Dette kan være uhyre nyttigt, når du udfører dyre beregninger eller opererer på store datasæt, så hovedtråden kan køre problemfrit, mens du udfører de dyre operationer på en eller flere baggrundstråde.

Her er et typisk eksempel på brug af arbejdstagere, hvor et arbejderscript lytter efter meddelelser fra hovedtråden og reagerer ved at sende sine egne meddelelser tilbage:

side.js:

const worker = new Worker('worker.js');
worker.addEventListener(e => {
console.log(e.data);
});
worker.postMessage('hello');

arbejder.js:

addEventListener('message', e => {
if (e.data === 'hello') {
postMessage('world');
}
});

INTERNETARBEJDERENS API har været tilgængelig i de fleste bro.Serere i over ti år. Selvom det betyder, at arbejdstagere har fremragende bro.ser-support og er godt optimeret, betyder det også, at de længe går forud for JavaScript-moduler. Da der ikke var noget modulsystem, da arbejdere blev designet, har API ‘ en til indlæsning af kode i en arbejdstager og komponering af scripts forblevet den samme som de synkrone scriptindlæsningsmetoder, der var almindelige i 2009.

historie: klassiske arbejdere #

Arbejderkonstruktøren tager en klassisk script-URL, som er i forhold til dokumentets URL. Det returnerer straks en henvisning til den nye arbejdstagerinstans, der udsætter en messaging-grænseflade samt en terminate() – metode, der straks stopper og ødelægger arbejdstageren.

const worker = new Worker('worker.js');

enimportScripts() funktion er tilgængelig inden for internetarbejdere til indlæsning af yderligere kode, men den sætter arbejderens udførelse på pause for at hente og evaluere hvert script. Det udfører også scripts i det globale omfang som et klassisk <script> tag, hvilket betyder, at variablerne i et script kan overskrives af variablerne i et andet.

arbejder.js:

importScripts('greet.js');
// ^ could block for seconds
addEventListener('message', e => {
postMessage(sayHello());
});

hilse.js:

// global to the whole worker
function sayHello() {
return 'world';
}

af denne grund har internetarbejdere Historisk pålagt en overdreven effekt på arkitekturen i en applikation. Udviklere har været nødt til at skabe smarte værktøjer og løsninger for at gøre det muligt at bruge internetarbejdere uden at opgive moderne udviklingspraksis. Som et eksempel integrerer bundlere en lille modullæsserimplementering i genereret kode, der bruger importScripts() til kodeindlæsning, men indpakker moduler i funktioner for at undgå variable kollisioner og simulere import og eksport af afhængighed.

indtast modularbejdere #

en ny tilstand til internetarbejdere med ergonomi og ydelsesfordele ved JavaScript-moduler leveres i Chrome 80, kaldet modularbejdere. Worker constructor accepterer nu en ny{type:"module"}, som ændrer scriptindlæsning og udførelse for at matche<script type="module">.

const worker = new Worker('worker.js', {
type: 'module'
});

da modularbejdere er standard JavaScript-moduler, kan de bruge import-og eksportopgørelser. Som med alle JavaScript-moduler udføres afhængigheder kun en gang i en given sammenhæng (hovedtråd, arbejdstager osv.), og al fremtidig import henviser til den allerede udførte modulinstans. Indlæsning og udførelse af JavaScript-moduler optimeres også af brugerne. Et moduls afhængigheder kan indlæses inden modulet udføres, hvilket gør det muligt at indlæse hele modultræer parallelt. Modulindlæsning cacher også parset kode, hvilket betyder moduler, der bruges på hovedtråden og i en arbejdstager, skal kun analyseres en gang.

flytning til JavaScript-moduler muliggør også brugen af dynamisk import til doven indlæsningskode uden at blokere udførelsen af arbejdstageren. Dynamisk import er meget mere eksplicit end at bruge importScripts() til at indlæse afhængigheder, da det importerede moduls eksport returneres snarere end at stole på globale variabler.

arbejder.js:

import { sayHello } from './greet.js';
addEventListener('message', e => {
postMessage(sayHello());
});

hilse.js:

import greetings from './data.js';
export function sayHello() {
return greetings.hello;
}

for at sikre god ydeevne er den gamleimportScripts() metode ikke tilgængelig inden for modularbejdere. At skifte arbejdere til at bruge JavaScript-moduler betyder, at al kode er indlæst i streng tilstand. En anden bemærkelsesværdig ændring er, at værdien af this i topniveau omfanget af et JavaScript-modul er undefined, mens værdien i klassiske arbejdere er arbejdstagerens globale omfang. Heldigvis har der altid været en self global, der giver en henvisning til det globale omfang. Den er tilgængelig i alle typer arbejdstagere, herunder servicearbejdere, såvel som i DOM.

Modularbejdere fjerner også understøttelse af HTML-stil kommentarer. Vidste du, at du kunne bruge HTML-kommentarer i scripts?

preload arbejdere med modulepreload #

en væsentlig præstationsforbedring, der følger med modularbejdere, er evnen til at preload arbejdere og deres afhængigheder. Med modularbejdere indlæses og udføres scripts som standard JavaScript-moduler, hvilket betyder, at de kan forudindlæses og endda forudparses ved hjælp af modulepreload:

<!-- preloads worker.js and its dependencies: -->
<link rel="modulepreload" href="worker.js">
<script>
addEventListener('load', () => {
// our worker code is likely already parsed and ready to execute!
const worker = new Worker('worker.js', { type: 'module' });
});
</script>

forudindlæste moduler kan også bruges af både hovedtråd og modularbejdere. Dette er nyttigt for moduler, der importeres i begge sammenhænge, eller i tilfælde, hvor det ikke er muligt på forhånd at vide, om et modul vil blive brugt på hovedtråden eller i en arbejdstager.

tidligere var de tilgængelige muligheder for forudindlæsning af netarbejderscripts begrænsede og ikke nødvendigvis pålidelige. Klassiske arbejdere havde deres egen” arbejdstager” – ressourcetype til forudindlæsning, men ingen bro.sere implementerede <link rel="preload" as="worker">. Som et resultat var den primære teknik, der var tilgængelig til Forudindlæsning af internetarbejdere, at bruge <link rel="prefetch">, som udelukkende var afhængig af HTTP-cachen. Når det bruges i kombination med de korrekte caching overskrifter, dette gjorde det muligt at undgå arbejdstager instantiation at skulle vente med at hente arbejdstager script. I modsætning til modulepreload understøttede denne teknik ikke forudindlæsningsafhængigheder eller præ-parsing.

hvad med delte arbejdere? #

delte arbejdere er blevet opdateret med understøttelse af JavaScript-moduler fra Chrome 83. Ligesom dedikerede arbejdere, konstruerer en delt arbejdstager med {type:"module"} indstillingen indlæser nu arbejderskriptet som et modul snarere end et klassisk script:

const worker = new SharedWorker('/worker.js', {
type: 'module'
});

før understøttelse af JavaScript-moduler forventede SharedWorker() konstruktøren kun en URL og en valgfri name argument. Dette vil fortsætte med at arbejde for klassisk delt medarbejderbrug; men at skabe modul delte arbejdere kræver at bruge den nyeoptions argument. De tilgængelige indstillinger er de samme som for en dedikeret arbejdstager, inklusive name, der erstatter det forrige name argument.

hvad med servicemedarbejder? #

servicemedarbejderens specifikation er allerede opdateret for at understøtte accept af et JavaScript-modul som indgangspunkt ved hjælp af den samme{type:"module"} mulighed som modularbejdere, men denne ændring er endnu ikke implementeret i Bro.sere. Når det sker, vil det være muligt at instantiere en servicemedarbejder ved hjælp af et JavaScript-modul ved hjælp af følgende kode:

navigator.serviceWorker.register('/sw.js', {
type: 'module'
});

nu hvor specifikationen er blevet opdateret, begynder bro.sere at implementere den nye adfærd. Dette tager tid, fordi der er nogle ekstra komplikationer forbundet med at bringe JavaScript-moduler til servicemedarbejder. Registrering af servicemedarbejdere skal sammenligne importerede scripts med deres tidligere cachelagrede versioner, når de bestemmer, om der skal udløses en opdatering, og dette skal implementeres for JavaScript-moduler, når de bruges til servicemedarbejdere. Servicemedarbejdere skal også være i stand til at omgå cachen til scripts i visse tilfælde, når de kontrollerer for opdateringer.