Hvordan fungerer Event Loop i JavaScript?

Selv om det kan kreve en grundig forståelse av språk som C++ og C for å skrive fullskala produksjonskode, kan JavaScript ofte skrives med bare en grunnleggende forståelse av hva som kan gjøres med språket.

Konsepter, som å sende tilbakeringinger til funksjoner eller skrive asynkron kode, er ofte ikke så vanskelig å implementere, noe som gjør at de fleste JavaScript-utviklere bryr seg mindre om hva som foregår under panseret. De bryr seg bare ikke om å forstå kompleksiteten som har dypt abstrahert fra dem av språket.

Som JavaScript-utvikler blir det stadig viktigere å forstå hva som egentlig skjer under panseret og hvordan de fleste av disse kompleksitetene som er abstrahert fra oss, virkelig fungerer. Det hjelper oss å ta mer informerte beslutninger, som igjen kan øke kodeytelsen vår drastisk.

Denne artikkelen fokuserer på et av de svært viktige, men sjeldent forståtte konseptene eller termene i JavaScript. EVENTSLOOPEN!.

Å skrive asynkron kode kan ikke unngås i JavaScript, men hvorfor betyr en kode som kjører asynkront egentlig? dvs. The Event Loop

Før vi kan forstå hvordan eventloopen fungerer, må vi først forstå hva JavaScript i seg selv er og hvordan det fungerer!

Hva er JavaScript?

Før vi fortsetter, vil jeg gjerne at vi tar et skritt tilbake til det helt grunnleggende. Hva er egentlig JavaScript? Vi kan definere JavaScript som;

JavaScript er et høyt nivå, tolket, enkelttrådet, ikke-blokkerende, asynkront, samtidig språk.

Vent, hva er dette? En boklig definisjon? 🤔

La oss bryte det ned!

Nøkkelordene her når det gjelder denne artikkelen er entrådede, ikke-blokkerende, samtidige og asynkrone.

Enkel tråd

En utførelsestråd er den minste sekvensen med programmerte instruksjoner som kan administreres uavhengig av en planlegger. Et programmeringsspråk er entrådet betyr at det bare kan utføre én oppgave eller operasjon om gangen. Dette betyr at den vil utføre en hel prosess fra start til slutt uten at tråden blir avbrutt eller stoppet.

I motsetning til flertrådede språk hvor flere prosesser kan kjøres på flere tråder samtidig uten å blokkere hverandre.

Hvordan kan JavaScript være entrådet og ikke-blokkerende på samme tid?

  Hvordan redigere bilder og videoer fra kamerarullen

Men hva betyr blokkering?

Ikke-blokkerende

Det er ingen definisjon av blokkering; det betyr rett og slett ting som går sakte på tråden. Så ikke-blokkering betyr ting som ikke er trege på tråden.

Men vent, sa jeg at JavaScript kjører på en enkelt tråd? Og jeg sa også at det ikke blokkerer, noe som betyr at oppgaven kjører raskt på anropsstakken? Men hvordan??? Hva med når vi kjører tidtakere? Løkker?

Slappe av! Det finner vi ut om litt 😉.

Samtidig

Samtidig betyr at koden kjøres samtidig av mer enn én tråd.

Ok, ting begynner å bli skikkelig merkelig nå, hvordan kan JavaScript være entråds og samtidig være samtidig? dvs. kjøre koden med mer enn én tråd?

Asynkron

Asynkron programmering betyr at koden kjører i en hendelsessløyfe. Når det er en blokkeringsoperasjon, startes hendelsen. Blokkeringskoden fortsetter å kjøre uten å blokkere hovedutførelsestråden. Når blokkeringskoden er ferdig å kjøre, er køen resultatet av blokkeringsoperasjonene og skyver dem tilbake til stabelen.

Men JavaScript har en enkelt tråd? Hva kjører da denne blokkeringskoden mens andre koder i tråden blir utført?

Før vi fortsetter, la oss få en oppsummering av det ovennevnte.

  • JavaScript er entråds
  • JavaScript er ikke-blokkerende, dvs. langsomme prosesser blokkerer ikke kjøringen
  • JavaScript er samtidig, dvs. det kjører koden sin i mer enn én tråd samtidig
  • JavaScript er asynkront, dvs. det kjører blokkeringskode et annet sted.

Men det ovenstående stemmer ikke akkurat, hvordan kan et enkelt-tråds språk være ikke-blokkerende, samtidig og asynkront?

La oss gå litt dypere, la oss gå ned til JavaScript-runtime-motorene, V8, kanskje den har noen skjulte tråder vi ikke er klar over.

V8 motor

V8-motoren er en høyytelses, åpen kildekode-kjøretidsmotor for nettmontering for JavaScript skrevet i C++ av Google. De fleste nettlesere kjører JavaScript ved å bruke V8-motoren, og til og med det populære node js runtime-miljøet bruker det også.

På enkelt engelsk er V8 et C++-program, som mottar JavaScript-kode, kompilerer og kjører den.

V8 gjør to store ting;

  • Tildeling av haugminne
  • Kontekst for utførelse av anropsstabel

Dessverre var mistanken vår feil. V8-en har bare én call-stabel, tenk på call-stabelen som tråden.

Én tråd === én anropsstabel === én utførelse om gangen.

  Slik fjerner du skriblerier på en skjermdump av iPhone

Bilde – Hacker Noon

Siden V8 bare har én anropsstabel, hvordan kjører da JavaScript samtidig og asynkront uten å blokkere hovedutførelsestråden?

La oss prøve å finne ut av det ved å skrive en enkel, men vanlig asynkron kode og analysere den sammen.

JavaScript kjører hver kode linje for linje, en etter hverandre (enkeltråd). Som forventet blir den første linjen skrevet ut i konsollen her, men hvorfor skrives den siste linjen ut før tidsavbruddskoden? Hvorfor venter ikke utførelsesprosessen på tidsavbruddskoden (blokkering) før den går videre til å kjøre den siste linjen?

En annen tråd ser ut til å ha hjulpet oss med å utføre den tidsavbruddet siden vi er ganske sikre på at en tråd bare kan utføre én enkelt oppgave til enhver tid.

La oss ta en sniktitt inn i V8 Kildekode en stund.

Vent… hva??!!! Det er ingen timerfunksjoner i V8, ingen DOM? Ingen arrangementer? Ingen AJAX?… Yeeeessss!!!

Hendelser, DOM, tidtakere osv. er ikke en del av JavaScripts kjerneimplementering, JavaScript er strengt i samsvar med Ecma Scripts-spesifikasjonene og ulike versjoner av det refereres ofte til i henhold til Ecma Scripts Specifications (ES X).

Arbeidsflyt for utførelse

Hendelser, tidtakere, Ajax-forespørsler leveres alle på klientsiden av nettleserne og blir ofte referert til som Web API. Det er de som lar entråds JavaScript være ikke-blokkerende, samtidig og asynkront! Men hvordan?

Det er tre hovedseksjoner i utførelsesarbeidsflyten til et hvilket som helst JavaScript-program, anropsstakken, web-API-en og oppgavekøen.

Anropsstakken

En stabel er en datastruktur der det siste elementet som ble lagt til alltid er det første som fjernes fra stabelen, du kan tenke på det som en stabel av en plate der bare den første platen som ble sist lagt til kan fjernes først. En anropsstakk er rett og slett ikke annet enn en stabeldatastruktur der oppgaver eller kode utføres deretter.

La oss vurdere eksemplet nedenfor;

Kilde – https://youtu.be/8aGhZQkoFbQ

Når du kaller funksjonen printSquare() , skyves den på anropsstakken, printSquare()-funksjonen kaller square()-funksjonen. Square()-funksjonen skyves inn på stabelen og kaller også multiply()-funksjonen. Multipliseringsfunksjonen skyves inn på stabelen. Siden multipliser-funksjonen returnerer og er den siste tingen som ble skjøvet til stabelen, løses den først og fjernes fra stabelen, etterfulgt av square()-funksjonen og deretter printSquare()-funksjonen.

  Slik slår du av Logitech Keyboard Number Lock

Web API

Det er her kode som ikke håndteres av V8-motoren kjøres for ikke å «blokkere» hovedutførelsestråden. Når anropsstakken støter på en web-API-funksjon, blir prosessen umiddelbart overlevert til web-APIen, hvor den utføres og frigjør anropsstakken til å utføre andre operasjoner under utførelsen.

La oss gå tilbake til vårt setTimeout-eksempel ovenfor;

Når vi kjører koden, blir den første console.log-linjen skjøvet til stabelen, og vi får utdataene våre nesten umiddelbart, når vi kommer til timeout, håndteres tidtakere av nettleseren og er ikke en del av V8s kjerneimplementering, den blir presset til Web API i stedet, og frigjør stabelen slik at den kan utføre andre operasjoner.

Mens tidsavbruddet fortsatt kjører, går stabelen videre til neste handlingslinje og kjører den siste console.log, som forklarer hvorfor vi får det utgitt før timerutgangen. Når tidtakeren er fullført, skjer det noe. console.log inn og så vises timeren på magisk vis i anropsstakken igjen!

Hvordan?

Event-sløyfen

Før vi diskuterer hendelsesløkken, la oss først gå gjennom funksjonen til oppgavekøen.

Tilbake til eksempelet vårt med tidsavbrudd, når Web API er ferdig med å utføre oppgaven, skyver den den ikke bare tilbake til anropsstakken automatisk. Den går til oppgavekøen.

En kø er en datastruktur som fungerer etter først inn først ut-prinsippet, så når oppgaver blir presset inn i køen, kommer de ut i samme rekkefølge. Oppgaver som har blitt utført av web-API-ene, som blir presset til oppgavekøen, går deretter tilbake til anropsstakken for å få resultatet skrevet ut.

Men vent. HVA i helvete ER EVENTSLOOPEN???

Kilde – https://youtu.be/8aGhZQkoFbQ

Hendelsesløkken er en prosess som venter på at anropsstakken er klar før tilbakeringing fra oppgavekøen til anropsstakken skyves. Når stakken er klar, utløses hendelsesløkken og sjekker oppgavekøen for tilgjengelige tilbakeringinger. Hvis det er noen, skyver den den til anropsstakken, venter på at anropsstakken er klar igjen, og gjentar den samme prosessen.

Kilde – https://www.quora.com/How-does-an-event-loop-work/answer/Timothy-Maxwell

Diagrammet ovenfor viser den grunnleggende arbeidsflyten mellom hendelsessløyfen og oppgavekøen.

Konklusjon

Selv om dette er en veldig grunnleggende introduksjon, gir konseptet med asynkron programmering i JavaScript nok innsikt til å tydelig forstå hva som foregår under panseret og hvordan JavaScript er i stand til å kjøre samtidig og asynkront med bare en enkelt tråd.

JavaScript er alltid on-demand, og hvis du er nysgjerrig på å lære, vil jeg råde deg til å sjekke ut dette Udemy kurs.