Articles

Verkon pujottaminen moduulityöntekijöillä

JavaScript on yksikierteistä, eli se voi suorittaa vain yhden toiminnon kerrallaan. Tämä on intuitiivinen ja toimii hyvin paljon tapauksia Webissä, mutta voi olla ongelmallista, kun meidän täytyy tehdä raskaita nostotehtäviä, kuten tietojenkäsittely, jäsennys, laskenta tai analyysi. Kun yhä monimutkaisempia sovelluksia toimitetaan verkossa, monisäikeisen käsittelyn tarve kasvaa.

verkkoalustalla tärkein ketjuttamisen ja yhdensuuntaisuuden primitiivinen muoto on Web Workers API. Työntekijät ovat kevyt abstraktio päälle käyttöjärjestelmän kierteet, jotka paljastavat viestin kulkee API inter-thread viestintä. Tämä voi olla erittäin hyödyllistä, kun suoritetaan kalliita laskelmia tai toimivat suurilla tietojoukoilla, jolloin pääkierre toimii sujuvasti suorittaessaan kalliita toimintoja yhdellä tai useammalla taustalangalla.

tässä on tyypillinen esimerkki työntekijän käytöstä, jossa työntekijä-skripti kuuntelee viestejä pääkierteeltä ja vastaa lähettämällä takaisin omia viestejä:

sivu.js:

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

työläinen.js:

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

Web Worker API on ollut käytettävissä useimmissa selaimissa yli kymmenen vuotta. Vaikka tämä tarkoittaa, että työntekijöillä on erinomainen selaintuki ja ovat hyvin optimoituja, se tarkoittaa myös, että he kauan ennen JavaScript-moduuleja. Koska työntekijöitä suunniteltaessa ei ollut moduulijärjestelmää, ohjelmointirajapinta koodin lataamiseen työntekijään ja skriptien säveltämiseen on pysynyt samanlaisena kuin vuonna 2009 yleistyneet synkroniset skriptien lataustavat.

historia: classic workers #

Työläiskonstruktori ottaa klassisen skriptin URL-osoitteen, joka on suhteessa dokumentin URL-osoitteeseen. Se palauttaa välittömästi viittauksen uuteen työntekijän instanssiin, joka paljastaa viestirajapinnan sekä terminate() metodin, joka välittömästi pysäyttää ja tuhoaa työntekijän.

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

An importScripts() funktio on käytettävissä verkkotyöntekijöissä lisäkoodin lataamista varten, mutta se keskeyttää työntekijän suorituksen jokaisen komentosarjan noutamiseksi ja arvioimiseksi. Se suorittaa myös skriptejä globaalissa ulottuvuudessa kuten klassinen <script> tag, eli yhden skriptin muuttujat voidaan korvata toisen muuttujilla.

työntekijä.js:

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

greet.JS:

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

tästä syystä verkkotyöntekijät ovat historiallisesti tyrkyttäneet sovelluksen arkkitehtuurille ylimitoitettua vaikutusta. Kehittäjien on täytynyt luoda näppäriä työkaluja ja kiertoteitä mahdollistaakseen verkkotyöntekijöiden käytön nykyaikaisista kehityskäytännöistä luopumatta. Esimerkiksi niputtajat kuten webpack upottavat pienen moduulilataajan toteutuksen generoituun koodiin, joka käyttää importScripts() koodin lataamiseen, mutta kietoo moduulit funktioihin välttääkseen vaihtelevia törmäyksiä ja simuloidakseen riippuvuutta tuonnista ja viennistä.

Enter module workers #

Uusi JavaScript-moduulien ergonomiaa ja suorituskykyä edistävä verkkotyöntekijöiden toimintatapa on Chrome 80, jota kutsutaan moduulityöntekijöiksi. Worker constructor hyväksyy nyt uuden {type:"module"} – vaihtoehdon, joka muuttaa komentosarjan lataamisen ja suorittamisen vastaamaan <script type="module">.

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

koska moduulityöntekijät ovat tavallisia JavaScript-moduuleja, he voivat käyttää tuonti-ja vientilausuntoja. Kuten kaikki JavaScript-moduulit, riippuvuudet suoritetaan vain kerran tietyssä yhteydessä (pääkierre, työntekijä jne.), ja kaikki tulevat tuonnit viittaavat jo toteutettuun moduuliesiintymään. JavaScript-moduulien lataus ja toteutus on myös optimoitu selaimilla. Moduulin riippuvuudet voidaan ladata ennen moduulin suorittamista, jolloin kokonaisia moduulipuita voidaan ladata rinnakkain. Moduulin lataus myös välimuistit jäsentää koodia, mikä tarkoittaa moduuleja, joita käytetään pääkierteessä ja työntekijällä tarvitsee jäsentää vain kerran.

JavaScript-moduuleihin siirtyminen mahdollistaa myös laiskasti lataavan koodin dynaamisen tuonnin estämättä työntekijän suoritusta. Dynaaminen tuonti on paljon selkeämpää kuin importScripts() kuormariippuvuuksien käyttäminen, koska tuodun moduulin vienti palautetaan sen sijaan, että luotaisiin globaaleihin muuttujiin.

työntekijä.js:

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

greet.js:

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

hyvän suorituskyvyn varmistamiseksi vanha importScripts() menetelmä ei ole käytettävissä moduulityöntekijöissä. Työntekijöiden vaihtaminen JavaScript-moduulien käyttöön tarkoittaa, että kaikki koodi ladataan tiukassa tilassa. Toinen merkittävä muutos on se, että this JavaScript-moduulin ylätason laajuudessa arvo on undefined, kun taas klassisissa työläisissä arvo on työntekijän globaali laajuus. Onneksi aina on ollut self globaali, joka antaa viitteen globaaliin ulottuvuuteen. Se on saatavilla kaikentyyppisille työntekijöille, mukaan lukien palvelutyöntekijät, sekä DOM.

Moduulityöntekijät poistavat myös tuen HTML-tyylisille kommenteille. Tiesitkö, että voit käyttää HTML-kommentteja web-työntekijöiden skripteissä?

esikuormitustyöntekijät modulepreload #

yksi merkittävä suorituskykyparannus, joka tulee moduulityöntekijöiden mukana, on kyky esikuormitustyöntekijöihin ja heidän riippuvuuksiinsa. Moduulityöntekijöillä skriptit Ladataan ja toteutetaan tavallisina JavaScript-moduuleina, eli ne voidaan esiladata ja jopa jäsentää käyttäen 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>

esiladattuja moduuleja voivat käyttää myös sekä pääkierteen että moduulityöntekijät. Tämä on hyödyllistä moduuleille, jotka tuodaan molemmissa yhteyksissä, tai tapauksissa, joissa ei ole mahdollista tietää etukäteen, käytetäänkö moduulia pääkierteessä vai työntekijässä.

aiemmin web worker-skriptien esilataukseen käytettävissä olevat vaihtoehdot olivat rajallisia eivätkä välttämättä luotettavia. Klassisilla työntekijöillä oli oma” worker” – resurssityyppi esilatausta varten, mutta yhtään selainta ei toteutettu <link rel="preload" as="worker">. Tämän seurauksena web-työntekijöiden ensisijainen käytettävissä oleva tekniikka oli käyttää <link rel="prefetch">, joka tukeutui täysin HTTP-välimuistiin. Kun sitä käytettiin yhdessä oikean välimuistin otsikoiden kanssa, se mahdollisti sen, ettei työntekijän instantiaation tarvinnut odottaa työntekijän skriptin lataamista. Toisin kuin modulepreload tämä tekniikka ei kuitenkaan tukenut preloading-riippuvuuksia tai pre-jäsennystä.

entä jaetut työntekijät? #

jaettuja työntekijöitä on päivitetty JavaScript-moduulien tuella Chrome 83: sta alkaen.{type:"module"} vaihtoehto Lataa nyt

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

ennen JavaScript-moduulien tukemista SharedWorker()rakentaja odotti vain URL-osoitetta ja valinnaista nameargumentti. Tämä toimii jatkossakin classic shared Workerin käytössä; jaettujen työntekijöiden moduulin luominen vaatii kuitenkin uuden options – argumentin käyttämistä. Käytettävissä olevat vaihtoehdot ovat samat kuin omistautuneella työntekijällä, mukaan lukien name vaihtoehto, joka syrjäyttää edellisen name argumentti.

entä palvelutyöntekijä? #

palvelutyöntekijän määrittely on jo päivitetty tukemaan JavaScript-moduulin hyväksymistä aloituspisteeksi käyttäen samaa {type:"module"} – vaihtoehtoa moduulityöntekijöinä, mutta tätä muutosta ei ole vielä toteutettu selaimissa. Kun tämä tapahtuu, on mahdollista asentaa Palveluntyöntekijä JavaScript-moduulin avulla seuraavalla koodilla:

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

nyt kun eritelmä on päivitetty, selaimet alkavat toteuttaa uutta käyttäytymistä. Tämä vie aikaa, koska on olemassa joitakin ylimääräisiä komplikaatioita tuo JavaScript moduulit service worker. Palvelutyöntekijän rekisteröinnin yhteydessä on verrattava tuotuja skriptejä aikaisempiin välimuistiin tallennettuihin versioihin, kun määritetään, käynnistetäänkö päivitys, ja tämä on toteutettava JavaScript-moduulien osalta, kun niitä käytetään palvelutyöntekijöille. Myös, palvelutyöntekijöiden täytyy pystyä ohittamaan välimuistin skriptejä tietyissä tapauksissa tarkistettaessa päivityksiä.