JavaScripts udførelsesmodel er nuanceret og let at misforstå. At lære om begivenhedsløkken i sin kerne kan hjælpe.

JavaScript er et enkelt-trådet sprog, bygget til at håndtere opgaver én ad gangen. Hændelsesløkken lader imidlertid JavaScript håndtere hændelser og tilbagekald asynkront ved at emulere samtidige programmeringssystemer. Dette sikrer ydelsen af ​​dine JavaScript-applikationer.

Hvad er JavaScript Event Loop?

JavaScripts hændelsesløkke er en mekanisme, der kører i baggrunden af ​​enhver JavaScript-applikation. Det tillader JavaScript at håndtere opgaver i rækkefølge uden at blokere dets hovedudførelsestråd. Dette omtales som asynkron programmering.

Hændelsesløkken holder en kø af opgaver, der skal køres, og feeder disse opgaver til højre web API til udførelse én ad gangen. JavaScript holder styr på disse opgaver og håndterer hver enkelt i henhold til opgavens kompleksitetsniveau.

For at forstå behovet for JavaScript-hændelsesløkke og asynkron programmering. Du skal forstå, hvilket problem det i bund og grund løser.

instagram viewer

Tag denne kode, for eksempel:

functionlongRunningFunction() {
// This function does something that takes a long time to execute.
for (var i = 0; i < 100000; i++) {
console.log("Hello")
}
}

functionshortRunningFunction(a) {
return a * 2 ;
}

functionmain() {
var startTime = Date.now();
longRunningFunction();

var endTime = Date.now();

// Prints the amount of time it took to execute functions
console.log(shortRunningFunction(2));
console.log("Time taken: " + (endTime - startTime) + " milliseconds");
}

main();

Denne kode definerer først en funktion kaldet longRunningFunction(). Denne funktion vil udføre en form for kompleks tidskrævende opgave. I dette tilfælde udfører den en til loop itererende over 100.000 gange. Det betyder at console.log("Hej") kører 100.000 gange.

Afhængigt af computerens hastighed kan dette tage lang tid og blokere shortRunningFunction() fra øjeblikkelig udførelse til den forrige funktion er fuldført.

For kontekst er her en sammenligning af den tid, det tager at køre begge funktioner:

Og så singlen shortRunningFunction():

Forskellen mellem en operation på 2.351 millisekunder og en operation på 0 millisekunder er indlysende, når du sigter efter at bygge en effektiv app.

Hvordan Event Loop hjælper med appens ydeevne

Eventloopet har forskellige stadier og dele, der er med til at få systemet til at fungere.

Opkaldsstakken

JavaScript-opkaldsstakken er afgørende for, hvordan JavaScript håndterer funktions- og hændelseskald fra din applikation. JavaScript-kode kompilerer fra top til bund. Men, Node.js, ved at læse koden, vil Node.js tildele funktionskald fra bunden til toppen. Mens den læser, skubber den de definerede funktioner som frames ind i opkaldsstakken én efter én.

Opkaldsstakken er ansvarlig for at vedligeholde udførelseskonteksten og den korrekte rækkefølge af funktioner. Det gør den ved at fungere som en Last-In-First-Out (LIFO) stak.

Det betyder, at den sidste funktionsramme, dit program skubber ind på opkaldsstakken, vil være den første, der springer ud af stakken og kører. Dette sikrer, at JavaScript bevarer den rigtige rækkefølge for funktionsudførelse.

JavaScript vil springe hver frame ud af stakken, indtil den er tom, hvilket betyder, at alle funktioner er færdige med at køre.

Libuv Web API

Kernen i JavaScripts asynkrone programmer er libuv. Libuv-biblioteket er skrevet i programmeringssproget C, som kan interagere med styresystemets API'er på lavt niveau. Biblioteket vil give flere API'er, der tillader JavaScript-kode at køre parallelt med andre kode. API'er til oprettelse af tråde, en API til kommunikation mellem tråde og en API til styring af trådsynkronisering.

For eksempel når du bruger setTimeout i Node.js for at sætte udførelse på pause. Timeren sættes op gennem libuv, som styrer hændelsesløkken for at udføre tilbagekaldsfunktionen, når den angivne forsinkelse er passeret.

På samme måde, når du udfører netværksoperationer asynkront, håndterer libuv disse operationer i en ikke-blokerende måde, der sikrer, at andre opgaver kan fortsætte behandlingen uden at vente på input/output (I/O) operationen ende.

Tilbagekalds- og begivenhedskøen

Tilbagekaldskøen og begivenhedskøen er, hvor tilbagekaldsfunktioner venter på udførelse. Når en asynkron operation afsluttes fra libuv, bliver dens tilsvarende tilbagekaldsfunktion tilføjet til denne kø.

Sådan går sekvensen:

  1. JavaScript flytter asynkrone opgaver til libuv, så det kan håndtere, og fortsætter med at håndtere den næste opgave med det samme.
  2. Når den asynkrone opgave er færdig, tilføjer JavaScript sin tilbagekaldsfunktion til tilbagekaldskøen.
  3. JavaScript bliver ved med at udføre andre opgaver i opkaldsstakken, indtil det er færdigt med alt i den aktuelle rækkefølge.
  4. Når opkaldsstakken er tom, ser JavaScript på tilbagekaldskøen.
  5. Hvis der er et tilbagekald i køen, skubber den den første ind på opkaldsstakken og udfører den.

På denne måde blokerer asynkrone opgaver ikke hovedtråden, og tilbagekaldskøen sikrer, at deres tilsvarende tilbagekald udføres i den rækkefølge, de afsluttede.

Event Loop Cycle

Hændelsesløkken har også noget, der kaldes mikrotask-køen. Denne særlige kø i begivenhedsløkken indeholder mikroopgaver, der er planlagt til at udføre, så snart den aktuelle opgave i opkaldsstakken er fuldført. Denne udførelse sker før den næste gengivelse eller hændelsesløkkeiteration. Mikroopgaver er højt prioriterede opgaver med forrang over almindelige opgaver i begivenhedsløkken.

En mikroopgave oprettes almindeligvis, når man arbejder med Promises. Når et løfte løses eller afvises, svarer det til det .derefter() eller .fangst() tilbagekald slutter sig til mikrotask-køen. Du kan bruge denne kø til at administrere opgaver, der skal udføres med det samme efter den aktuelle handling, såsom opdatering af brugergrænsefladen for din applikation eller håndtering af tilstandsændringer.

For eksempel en webapplikation, der udfører datahentning og opdaterer brugergrænsefladen baseret på de hentede data. Brugere kan udløse denne datahentning ved at klikke på en knap gentagne gange. Hvert knapklik starter en asynkron datahentningsoperation.

Uden mikroopgaver ville begivenhedsløkken for denne opgave fungere som følger:

  1. Brugeren klikker på knappen gentagne gange.
  2. Hvert knapklik udløser en asynkron datahentningsoperation.
  3. Efterhånden som datahentningsoperationerne er færdige, tilføjer JavaScript deres tilsvarende tilbagekald til den almindelige opgavekø.
  4. Hændelsesløkken begynder at behandle opgaver i den almindelige opgavekø.
  5. UI-opdateringen baseret på datahentningsresultaterne udføres, så snart de almindelige opgaver tillader det.

Men med mikroopgaver fungerer begivenhedsløkken anderledes:

  1. Brugeren klikker gentagne gange på knappen og udløser en asynkron datahentningsoperation.
  2. Efterhånden som datahentningsoperationerne er færdige, tilføjer hændelsesløkken deres tilsvarende tilbagekald til mikrotask-køen.
  3. Hændelsesløkken begynder at behandle opgaver i mikroopgavekøen umiddelbart efter at have afsluttet den aktuelle opgave (knapklik).
  4. UI-opdateringen baseret på datahentningsresultaterne udføres før den næste almindelige opgave, hvilket giver en mere responsiv brugeroplevelse.

Her er et kodeeksempel:

const fetchData = () => {
returnnewPromise(resolve => {
setTimeout(() => resolve('Data from fetch'), 2000);
});
};

document.getElementById('fetch-button').addEventListener('click', () => {
fetchData().then(data => {
// This UI update will run before the next rendering cycle
updateUI(data);
});
});

I dette eksempel kalder hvert klik på "Hent"-knappen fetchData(). Hver datahentningsoperationsplaner som en mikroopgave. Baseret på de hentede data udføres UI-opdateringen umiddelbart efter, at hver hentehandling er fuldført, før alle andre gengivelses- eller hændelsesløkkeopgaver.

Dette sikrer, at brugerne ser de opdaterede data uden at opleve forsinkelser på grund af andre opgaver i hændelsesløkken.

Brug af mikroopgaver i scenarier som dette kan forhindre UI-fejl og give hurtigere og smidigere interaktioner i din applikation.

Implikationer af Event Loop for webudvikling

At forstå begivenhedsløkken og hvordan man bruger dens funktioner er afgørende for at opbygge effektive og responsive applikationer. Hændelsesløkken giver asynkrone og parallelle muligheder, så du effektivt kan håndtere komplekse opgaver i din applikation uden at gå på kompromis med brugeroplevelsen.

Node.js giver alt, hvad du har brug for, inklusive webarbejdere for at opnå yderligere parallelitet uden for JavaScripts hovedtråd.