Articles

Tråder på nettet med modularbeidere

JavaScript er enkelttrådet, noe som betyr at Det bare kan utføre en operasjon om gangen. Dette er intuitivt og fungerer bra for mange tilfeller på nettet, men kan bli problematisk når vi trenger å gjøre tunge løfteoppgaver som databehandling, parsing, beregning eller analyse. Etter hvert som flere og flere komplekse applikasjoner leveres på nettet, er det et økt behov for multi-threaded behandling.

på nettplattformen er Den viktigste primitive for tråder og parallellisme Web Workers API. Arbeidere er en lett abstraksjon på toppen av operativsystemtråder som avslører EN melding som passerer API for inter-trådkommunikasjon. Dette kan være svært nyttig når du utfører kostbare beregninger eller opererer på store datasett, slik at hovedtråden kan kjøre jevnt mens du utfører de dyre operasjonene på en eller flere bakgrunns tråder.

Her er et typisk eksempel på worker-bruk, der et worker-skript lytter etter meldinger fra hovedtråden og svarer ved å sende tilbake egne meldinger:

side.js:

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

arbeider.js:

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

Web Worker API har vært tilgjengelig i de fleste nettlesere i over ti år. Selv om det betyr at arbeidere har utmerket nettleserstøtte og er godt optimalisert, betyr det også at De lenge er eldre Enn JavaScript-moduler. SIDEN det ikke var noe modulsystem da arbeidere ble designet, HAR API for å laste inn kode i en arbeidstaker og komponere skript vært lik de synkrone skriptlastningsmetodene som var vanlige i 2009.

Historikk: klassiske arbeidere #

arbeidskonstruktøren tar en KLASSISK skriptadresse, som er i forhold til dokumentadressen. Den returnerer umiddelbart en referanse til den nye worker-forekomsten, som viser et meldingsgrensesnitt, samt en terminate() – metode som umiddelbart stopper og ødelegger arbeideren.

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

En importScripts() funksjonen er tilgjengelig i webarbeidere for å laste inn tilleggskode, men den stopper utførelsen av arbeideren for å hente og evaluere hvert skript. Den utfører også skript i det globale omfanget som en klassisk<script> tag, noe som betyr at variablene i ett skript kan overskrives av variablene i en annen.

arbeider.js:

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

hilse på.js:

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

av denne grunn har webarbeidere historisk pålagt en overdimensjonert effekt på arkitekturen til et program. Utviklere har måttet lage smarte verktøy og løsninger for å gjøre det mulig å bruke webarbeidere uten å gi opp moderne utviklingspraksis. Som et eksempel, bundlers som webpack bygge inn en liten modul loader implementering i generert kode som bruker importScripts() for kode lasting, men brytes moduler i funksjoner for å unngå variable kollisjoner og simulere avhengighet import og eksport.

Skriv inn modularbeidere #

en ny modus For webarbeidere Med ergonomi og ytelsesfordeler Ved JavaScript-moduler, sendes i Chrome 80, kalt modularbeidere. Worker konstruktøren aksepterer nå en ny {type:"module"} alternativet, som endrer skriptinnlasting og utførelse for å matche <script type="module">.

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

siden modularbeidere er Standard JavaScript-moduler, kan de bruke import og eksport uttalelser. Som med Alle JavaScript-moduler, blir avhengigheter bare utført en gang i en gitt kontekst(hovedtråd, arbeidstaker, etc.), og all fremtidig import refererer til den allerede utførte modulforekomsten. Lasting og utførelse Av JavaScript-moduler er også optimalisert av nettlesere. En modul avhengigheter kan lastes før modulen blir utført, noe som gjør at hele modulen trær som skal lastes i parallell. Modul lasting også bufrer analysert kode, som betyr moduler som brukes på hovedtråden og i en arbeidstaker trenger bare å bli analysert en gang.

Flytting Til JavaScript-moduler muliggjør også bruk av dynamisk import for lat-lasting kode uten å blokkere kjøring av arbeideren. Dynamisk import er mye mer eksplisitt enn å bruke importScripts() for å laste avhengigheter, siden den importerte modulens eksport returneres i stedet for å stole på globale variabler.

arbeider.js:

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

hilse på.js:

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

for å sikre god ytelse, er den gamle importScripts() metoden ikke tilgjengelig i modularbeidere. Bytte arbeidere til Å bruke JavaScript-moduler betyr at all kode er lastet i streng modus. En annen merkbar endring er at verdien av this i toppnivå omfanget Av En JavaScript-modul er undefined, mens i klassiske arbeidere verdien er arbeiderens globale omfang. Heldigvis har det alltid vært enself global som gir en referanse til det globale omfanget. Den er tilgjengelig i alle typer arbeidere, inkludert servicearbeidere, SAMT I DOM.

Modul arbeidere også fjerne støtte FOR HTML-stil kommentarer. Visste du at DU kan bruke HTML kommentarer i web worker skript?

Preload arbeidere med modulepreload #

en betydelig ytelsesforbedring som følger med modularbeidere er muligheten til å preload arbeidere og deres avhengigheter. Med modularbeidere lastes skript og utføres som standard JavaScript-moduler, noe som betyr at de kan forhåndslastes og til og med forhåndsanalyseres ved hjelp av 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>

Forhåndslastede moduler kan også brukes av både hovedtråden og modularbeiderne. Dette er nyttig for moduler som importeres i begge sammenhenger, eller i tilfeller der det ikke er mulig å vite på forhånd om en modul skal brukes på hovedtråden eller i en arbeider.

tidligere var alternativene for forhåndsinnlasting av webarbeiderskript begrenset og ikke nødvendigvis pålitelige. Classic workers hadde sin egen» worker «ressurstype for forhåndsinnlasting ,men ingen nettlesere implementerte <link rel="preload" as="worker">. Som et resultat var den primære teknikken tilgjengelig for forhåndsinnlasting av webarbeidere å bruke <link rel="prefetch">, som var helt avhengig AV HTTP-hurtigbufferen. Når det brukes i kombinasjon med de riktige caching-overskriftene, gjorde dette det mulig å unngå at arbeideren måtte vente med å laste ned worker-skriptet. Men i motsetning tilmodulepreload denne teknikken ikke støtter preloading avhengigheter eller pre-parsing.

hva med delte arbeidere? #

Delte arbeidere har blitt oppdatert med støtte For JavaScript-moduler fra Chrome 83. Som dedikerte arbeidere, bygger en delt arbeidstaker med {type:"module"} alternativet laster nå arbeideren skriptet som en modul i stedet for et klassisk skript:

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

før støtte Av JavaScript-moduler, forventet SharedWorker() konstruktøren bare EN URL og en valgfri name argument. Dette vil fortsette å fungere for klassisk delt arbeidstaker bruk; men å opprette modul delte arbeidere krever bruk av det nyeoptions argumentet. De tilgjengelige alternativene er de samme som for en dedikert arbeider, inkludertname – alternativet som erstatter det forrigename – argumentet.

hva med servicearbeider? #

tjenestearbeiderspesifikasjonen er allerede oppdatert for å støtte å godta En JavaScript-modul som inngangspunkt, ved hjelp av samme {type:"module"} alternativ som modularbeidere, men denne endringen har ennå ikke blitt implementert i nettlesere. Når det skjer, vil det være mulig å instantiere en servicearbeider ved hjelp Av En JavaScript-modul ved hjelp av følgende kode:

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

nå som spesifikasjonen er oppdatert, begynner nettlesere å implementere den nye oppførselen. Dette tar tid fordi det er noen ekstra komplikasjoner forbundet med å bringe JavaScript-moduler til service worker. Servicearbeiderregistrering må sammenligne importerte skript med tidligere bufrede versjoner når du bestemmer om du vil utløse en oppdatering, og dette må implementeres For JavaScript-moduler når de brukes for servicearbeidere. Servicearbeidere må også kunne omgå hurtigbufferen for skript i visse tilfeller når de ser etter oppdateringer.