händelseslinga i nod js

Handelseslinga I Nod Js



Node.js är ett kraftfullt Javascript-ramverk som gör det möjligt för användare att köra Javascript-kod på servern utanför webbläsaren. Det är en icke-blockerande, händelsedriven runtime-miljö för att bygga pålitliga skalbara webbapplikationer. Händelseloopen är en viktig del av Node.js som gör att du kan utföra uppgifter utan att vänta på att en ska avslutas innan du startar en annan.

Även om Javascript är ett entrådigt språk, kan Node.js tilldela uppgifter till operativsystemet, vilket gör att det kan bearbeta flera uppgifter samtidigt. Flera uppgifter måste slutföras samtidigt eftersom operationerna i operativsystemet är flertrådade. Återuppringningen associerad med varje operation läggs till i händelsekön och schemaläggs av Node.js att köras när den angivna uppgiften är klar.

För att skriva effektiv och pålitlig Node.js-kod måste användaren ha en gedigen förståelse för händelseslingor. Det kan också hjälpa till att felsöka prestandaproblem effektivt. Händelseloopen i Node.js sparar minne och låter dig göra flera saker samtidigt utan att behöva vänta på att var och en ska slutföra. Termen 'asynkron' hänvisar till alla Javascript-funktioner som körs i bakgrunden utan att blockera inkommande förfrågningar.







Innan vi hoppar direkt till händelseloopar, låt oss ta en titt på olika aspekter av Javascript-programmeringsspråket.



Javascript som ett asynkront programmeringsspråk

Låt oss ta en titt på begreppen asynkron programmering. Javascript används i webb-, mobil- och stationära applikationer, men det bör noteras att Javascript är ett entrådigt, synkront datorprogrammeringsspråk.



Ett enkelt kodexempel ges för att förstå konceptet.





funktionsmetod 1 ( ) {

trösta. logga ( 'Funktion 1' )

}

funktionsmetod 2 ( ) {

trösta. logga ( 'Funktion 2' )

}

metod1 ( )

metod2 ( )

I den här koden skapas två enkla funktioner och metod1 anropas först så att den loggar metod1 först och sedan flyttas till nästa.

Produktion



Javascript som ett synkront programmeringsspråk

Javascript är ett synkront programmeringsspråk och exekverar varje rad steg för steg från topp till botten med endast en rad exekverad åt gången. I exemplet ovan loggas metod1 först i terminalen och sedan metod2.

Javascript som blockeringsspråk

Att vara ett synkront språk har javascript en blockerande funktion. Det spelar ingen roll hur lång tid det tar att slutföra en pågående process men en ny process kommer inte att startas förrän den föregående har slutförts. Anta i ovanstående kodexempel att det finns mycket kodskript i metod1 oavsett hur lång tid det tar, antingen 10 sekunder eller en minut kommer metod2 inte att exekveras förrän all kod i metod1 har exekveras.

Användare kan ha upplevt detta när de surfade. När en webbapplikation körs i en webbläsare i back-end exekveras en enorm kodbit så att webbläsaren verkar vara frusen under en tid innan kontrollåtkomsten returneras till användaren. Detta beteende är känt som blockering. Webbläsaren kan inte ta emot ytterligare inkommande förfrågningar förrän den aktuella förfrågan har behandlats.

Javascript är ett entrådigt språk

För att köra ett program i javascript används trådfunktionaliteten. Trådar kan bara utföra en uppgift åt gången. Andra programmeringsspråk stöder multi-threading och kan köra flera uppgifter parallellt, javascript innehåller bara en tråd för exekvering av valfritt kodskript.

Väntar i Javascript

Som framgår av namnet i det här avsnittet måste vi vänta på att vår begäran behandlas för att gå vidare. Väntan kan ta flera minuter under vilken ingen ytterligare begäran tas emot. Om kodskriptet fortsätter utan att vänta kommer koden att stöta på ett fel. Viss funktionalitet ska implementeras i Javascript eller mer specifikt Node.js för att göra koden asynkron.

Nu när vi har förstått de olika aspekterna av Javascript, låt oss förstå synkron och asynkron med några enkla exempel.

Synkron exekvering av kod i Javascript

Synkron betyder att koden exekveras sekventiellt eller enklare steg-för-steg med början uppifrån och rör sig nedåt rad för rad.

Nedan ges ett exempel som kan hjälpa till att förstå:

// application.js

trösta. logga ( 'Ett' )

trösta. logga ( 'Två' )

trösta. logga ( 'Tre' )

I den här koden finns det tre console.log-satser som var och en skriver ut något. Först skickas den första satsen som ska skrivas ut 'One' i konsolen till samtalsstacken i 1 ms (uppskattat) och sedan loggas den till terminalen. Efter det skjuts den andra satsen in i anropsstacken och nu är tiden 2 ms med en tillagd från föregående och sedan loggar den 'Två' till konsolen. Slutligen, det sista uttalandet skjuts in i samtalsstacken för nu är tiden 3ms och den loggar 'Tre' i konsolen.

Ovanstående kod kan exekveras genom att anropa följande kommando:

nodapplikation. js

Produktion

Funktionen förklaras ovan i detalj och genom att ta hänsyn till den loggas utgången in i konsolen på ett ögonblick:

Asynkron exekvering av kod i Javascript

Låt oss nu återställa samma kod genom att introducera återuppringningar och göra koden asynkron. Ovanstående kod kan återställas som:

// application.js
funktion printOne ( ring tillbaka ) {
setTimeout ( fungera ( ) {
trösta. logga ( 'Ett' ) ;
ring tillbaka ( ) ;
} , 1000 ) ;
}
funktion printTwo ( ring tillbaka ) {
setTimeout ( fungera ( ) {
trösta. logga ( 'Två' ) ;
ring tillbaka ( ) ;
} , 2000 ) ;
}
funktion printThree ( ) {
setTimeout ( fungera ( ) {
trösta. logga ( 'Tre' ) ;
} , 3000 ) ;
}
trösta. logga ( 'Start av programmet' ) ;
printOne ( fungera ( ) {
printTvå ( fungera ( ) {
printThree ( ) ;
} ) ;
} ) ;
trösta. logga ( 'Slutet på programmet' ) ;

I den här koden ovan:

  • Tre funktioner är deklarerade att skriva ut 'En', 'Två' och 'Tre', varje funktion har en återuppringningsparameter som tillåter sekventiell exekvering av kod.
  • En timeout ställs in med hjälp av setTimeout-funktionen och det finns en console.log-sats för utskrift efter en viss fördröjning.
  • Två meddelanden skrivs ut 'Start av programmet' och 'Programslut' som anger början och slutet av programmet.
  • Programmet startar med att skriva ut 'Start of the Program' varefter printOne-funktionen exekveras med en 1-sekunds fördröjning, sedan exekveras printTwo-funktionen med 2-sekunders fördröjning, och slutligen exekveras printThree-funktionen med 3-sekunders fördröjning. dröjsmål.
  • Programmet väntar inte på de asynkrona kodexekveringarna i setTimeouts-funktionerna som loggar 'Programslut'-satsen innan de skriver ut One, Two och Three.

Produktion

Kör ovanstående kod genom att utföra detta kommando i terminalen:

nodapplikation. js

Nu skulle utgången i terminalen dyka upp asynkront som:

Nu när vi har en fullständig förståelse för den synkrona och asynkrona exekveringen, låt oss hoppa för att befästa vårt koncept med händelseslinga i Node.js.

Node.js: Event Loop Mechanism

Exekveringen av både synkrona och asynkrona uppgifter hanteras av händelseslingan i Node.js. Exekveringen anropas så snart Node.js-projektet startar och överför smidigt de komplexa uppgifterna till systemet. Detta säkerställer att andra uppgifter kan löpa smidigt på huvudtråden.

Visuell förklaring av Event Loop i Node.js

Händelseloopen är kontinuerlig och semi-oändlig i Node.js. Händelseloopen anropas av starten av Node.js-kodskriptet, och den ansvarar för att göra asynkrona API-anrop och anropa processer.Tick(), och schemaläggningstimers återupptar sedan exekveringen av händelseslingan.

I Node.js hanterar fem huvudtyper av köer återuppringningar:

  • 'Timer Queue' allmänt känd som en min-heap är ansvarig för att hantera återuppringningar associerade med 'setTimeout' och 'setInterval'.
  • Återuppringningar för asynkrona operationer som i 'fs' och 'http' moduler hanteras av 'I/O Queue'.
  • 'Check Queue' innehåller callbacks för 'setImmediate'-funktionen som är unik för Node.
  • 'Stäng kö' hanterar återuppringningar associerade med alla asynkrona uppgifters stängningshändelse.
  • Slutligen finns det två olika köer i 'Micro Task'-kön:
    • 'nextTick'-kön innehåller återuppringningar associerade med 'process.nextTick'-funktionen.
    • 'Promise'-kön styr återuppringningar relaterade till inhemska Promise.

Event Loop-funktionalitet i Node.js

Händelseloopen fungerar enligt specifika krav som styr ordern om återuppringning. Användarens synkrona Javascript-kod prioriteras i början av processen, så händelseslingan startar först när anropsstacken rensas. Följande exekveringssekvens följer ett strukturerat mönster:

Högsta prioritet ges till återuppringningar i mikrouppgiftskön som sedan flyttar för att utföra uppgifterna i nästaTick-kö följt av uppgifterna i Löftekön. Processerna i timerns köåteruppringningar hanteras sedan, varefter mikrouppgiftskön återbesöks efter varje timeråteruppringning. Återuppringningarna i I/O-, kontroll- och stängköerna exekveras sedan i ett liknande mönster med mikrouppgiftskön som besöks efter varje fas.

Slingan fortsätter att köras om det finns fler återuppringningar att bearbeta. När kodskriptet har avslutats eller inga återuppringningar finns kvar att bearbeta, avslutas händelseslingan effektivt.

Nu när vi förstår händelseslingan på djupet, låt oss titta på dess funktioner.

Funktioner i händelseslingan i Node.js

Huvudfunktionerna är:

  • Händelseloopen är en oändlig loop och fortsätter att utföra uppgifterna så fort den tar emot dem och går in i viloläge om det inte finns några uppgifter men börjar fungera så snart uppgiften tas emot.
  • Uppgifterna i händelsekön exekveras endast när stacken är tom betyder att det inte finns någon aktiv operation.
  • Återuppringningar och löften kan användas i evenemangsslingan.
  • Eftersom händelseslingan följer principen för abstrakt datatypskö fyller den den första uppgiften och fortsätter sedan till nästa.

Efter en grundlig förståelse av händelseslingan och logiken i asynkrona och synkrona exekveringar, kan en förståelse för de olika faserna förstärka begreppen i händelseslingan.

Node.js Event loop Phases

Som nämnts ovan är händelseslingan semi-oändlig. Den har många faser men vissa faser används för intern hantering. Dessa faser har ingen effekt på kodskriptet.

Händelseloopen följer funktionaliteten i Queue och utför uppgiften enligt principen först in och först ut. De schemalagda timerna kommer att hanteras av operativsystemet tills de löper ut. De utgångna tidtagarna läggs sedan till i återuppringningskön för timers.

Händelseloopen utför uppgifterna i timerns kö en efter en tills det inte finns fler uppgifter kvar eller den når det maximalt tillåtna antalet uppgifter. I avsnitten nedan förklaras kärnfaserna för händelseslingor.

Timers fas

I Node.js finns ett timer-API som kan schemalägga de funktioner som ska köras i framtiden. Efter att den tilldelade tiden har passerat kommer timeråteruppringningen att utföras så snart de kan schemaläggas; dock kan en fördröjning uppstå antingen från operativsystemets ände eller på grund av att andra återuppringningar utförs.

Timers API har tre huvudfunktioner:

  • setTimeout
  • inställ omedelbart
  • setInterval

De ovan nämnda funktionerna är synkrona. Timerfasen i händelseslingan har sin omfattning begränsad till funktionerna setTimeout och setInterval. Medan kontrollfunktionen hanterar setImmediate-funktionen.

Låt oss överväga ett enkelt exempel för att befästa den teoretiska delen:

// application.js

funktion fördröjdFunktion ( ) {

trösta. logga ( 'den fördröjda funktionen exekveras efter timeout' ) ;

}

trösta. logga ( 'Start av programmet' ) ;

setTimeout ( delayedFunction, 2000 ) ;

trösta. logga ( 'Slutet på programmet' ) ;

I denna kod:

  • Programmet startar med att logga påståendet 'Start av programmet' till terminalen.
  • Sedan anropas delayedFunction med en timer på 2ms, kodskriptet stannar inte och fortsätter att hantera fördröjningen i bakgrunden.
  • Uttalandet ”Programslut loggas efter det första uttalandet.
  • Efter en fördröjning på 2ms loggas uttalandet i delayedFunction till terminalen.

Produktion

Utgången kommer att visas som:

Det kan ses att koden inte stoppas för att den delayedFunction ska bearbetas; den går framåt och efter fördröjningen bearbetas funktionen återuppringning.

Väntande återuppringningar

Händelseloopen kontrollerar de händelser som händer, som att läsa filer, nätverksaktiviteter eller inmatnings-/utdatauppgifter, i pollingfasen. Det är viktigt att veta att i Node.js hanteras bara några av händelserna i denna omröstningsfas. I den efterföljande iterationen av händelseslingan kan dock vissa händelser skjutas upp till den pågående fasen. Detta är ett nyckelbegrepp att tänka på vid optimering och felsökning av Node.js-kod som involverar komplexa händelsedrivna operationer.

Det är viktigt att förstå att under den väntande återuppringningsfasen lägger händelseslingan till uppskjutna händelser till kön av väntande återuppringningar och utför dem. Denna fas hanterar även vissa TCP-socket-fel som systemet har genererat, såsom ECONNREFUSED-felhändelser på vissa operativsystem.

Nedan nämns ett exempel för att befästa konceptet:

// application.js
konst fs = behöva ( 'fs' ) ;
funktion readFileAsync ( filsökväg, återuppringning ) {
fs. läsfil ( './PromiseText.txt' , 'utf8' , funktion ( fel, data ) {
om ( fela ) {
trösta. fel ( ` Fel läsa filen : $ { fela. meddelande } ` ) ;
} annan {
trösta. logga ( ` Fil innehåll : $ { data } ` ) ;
}
ring tillbaka ( ) ;
} ) ;
}
trösta. logga ( 'Start av programmet' ) ;
readFileAsync ( './PromiseText.txt' , funktion ( ) {
trösta. logga ( 'Fil läs återuppringning utförd' ) ;
} ) ;
trösta. logga ( 'Slutet på programmet' ) ;

I denna kod:

  • Programmet initieras genom att logga påståendet 'Start av programmet' i terminalen.
  • ReadFileAsync definieras asynkront för att läsa innehållet i filen 'PromiseText.txt'. Det är en parametriserad funktion som utför en återuppringningsfunktion efter att filen har lästs.
  • ReadFileAsync-funktionen anropas för att påbörja processen för filläsning.
  • Under filläsningen stannar inte programmet; istället fortsätter den till nästa programsats och loggar in den i terminalen 'Programslut'.
  • Den asynkrona händelsen för filläsning bearbetas i bakgrunden av händelseslingan.
  • Efter att filen har lästs asynkront och innehållet har loggats till terminalen loggar programmet filinnehållet till terminalen. Efter det loggar den följande meddelande 'File read callback utförd'.
  • Händelseloopen hanterar de pågående callback-operationerna i nästa fas.

Produktion

Resultatet av ovanstående exekvering är:

Inaktiv, förbered fasen i Node.js

Den inaktiva fasen används för att hantera interna funktioner i Node.js så det är inte en standardfas. Det påverkar inte kodskriptet. Den inaktiva fasen är som en pausperiod för händelseslingan under vilken hanterar de lågprioriterade uppgifterna i bakgrunden. Ett enkelt exempel för att förstå denna fas är:

konst { på tomgång } = behöva ( 'tom-gc' ) ;

på tomgång. ignorera ( ) ;

I den här koden används modulen 'idle-gc' som gör det möjligt att ignorera vilofasen. Detta tjänar till att hantera situationer när händelseslingan är upptagen och bakgrundsuppgifter inte utförs. Användningen av idle.ignore anses inte vara optimal eftersom det kan orsaka prestandaproblem.

Omröstningsfas i Node.js

Omröstningsfasen i Node.js fungerar som:

  • Den hanterar händelserna i omröstningskön och utför deras motsvarande uppgifter.
  • Den bestämmer hur mycket tid som ska ägnas åt att vänta och kontrollera I/O-operationerna i processen.

När händelseslingan går in i avfrågningsfasen på grund av frånvaron av en timer kommer en av nedanstående uppgifter att utföras:

  • I avfrågningsfasen av händelseslingan i Node.js ställs de väntande I/O-händelserna i kö och exekveras sedan i en sekventiell procedur enligt principen First In och First Out tills kön blir tom. Under återuppringningskörningarna är nästaTick- och microtasks-köerna också i aktion. Detta säkerställer smidighet och gör det möjligt att hantera I/O-operationer mer effektivt och tillförlitligt.
  • Om kön är tom och skriptet inte har schemalagts av setImmediate()-funktionen kommer händelseslingan att avslutas och den fortsätter till nästa fas(check). Å andra sidan, om skriptschemaläggningen har gjorts av setImmediate()-funktionen tillåter händelseslingan att återuppringningar läggs till i kön som kommer att exekveras av den.

Detta illustreras bäst med ett enkelt kodexempel:

setTimeout ( ( ) => {

trösta. logga ( 'Asynkroniseringsåtgärd slutförd' ) ;

} , 2000 ) ;

trösta. logga ( 'Start' ) ;

inställ omedelbart ( ( ) => {

trösta. logga ( 'setOmedelbar återuppringning utförd' ) ;

} ) ;

trösta. logga ( 'Slutet' ) ;

I denna kod:

  • Två meddelanden 'Start' och 'End' indikerar initiering och avslutning av programmet.
  • Funktionen setTimeout() ställer in en återuppringningsfunktion med en fördröjning på 2 ms och loggar 'Async operation completed' till terminalen.
  • Funktionen setImmediate() loggar meddelandet 'setImmediate callback executed' till terminalen efter att Startmeddelandet har loggats till terminalen.

Produktion

Utdata skulle visa meddelandena med bara en minuts observation att 'Async operation completed' tar tid och skrivs ut efter 'End'-meddelandet:

Node.js Kontrollera fas

Efter att avfrågningsfasen har utförts exekveras återuppringningarna i kontrollfasen. Om ett kodskript är schemalagt med funktionen setImmediate() och pollfunktionen är ledig, fungerar händelseslingan genom att gå direkt till kontrollfasen istället för att förbli inaktiv. Funktionen setImmediate() är en unik timer som fungerar under de olika faserna av händelseslingan.

libuv API används för att planera återuppringningskörningarna efter att undersökningsfasens exekvering har slutförts. Under kodexekveringen går händelseslingan in i avfrågningsfasen i vilken den väntar på inkommande anslutningsbegäranden. I ett annat fall, om återuppringningen är schemalagd med funktionen setImmediate() och avfrågningsfasen avslutas utan någon aktivitet kommer den att gå till kontrollfasen istället för att vänta. Betrakta exemplet nedan för förståelse:

// application.js

trösta. logga ( 'Start' ) ;

inställ omedelbart ( ( ) => {

trösta. logga ( 'Omedelbar återuppringning' ) ;

} ) ;

trösta. logga ( 'Slutet' ) ;

I denna kod loggas tre meddelanden in på terminalen. Funktionen setImmediate() skickar sedan äntligen en återuppringning för att logga meddelandet ' Omedelbar återuppringning ” till terminalen.

Produktion

Utdata från ovanstående kod kommer att dyka upp i följande sekvens:

Node.js stänger återuppringningar

Node.js använder denna stängningsfas för att köra callbacks för att stänga händelser och avsluta en händelseloopiteration. Efter att anslutningen stängts hanterar händelseslingan stängningshändelserna i denna fas. I denna fas av händelseslingan genereras och bearbetas 'nextTick()' och mikrouppgifter på samma sätt som andra faser.

Process.exit-funktionen används för att avsluta händelseslingan när som helst. Händelseloopen kommer att bortse från alla pågående asynkrona operationer och Node.js-processen kommer att avslutas.

Ett enkelt exempel att tänka på är:

// application.js
konst netto = behöva ( 'netto' ) ;
konst server = netto. skapaServer ( ( uttag ) => {
uttag. ( 'stänga' , ( ) => {
trösta. logga ( 'Uttaget stängt' ) ;
} ) ;
uttag. ( 'data' , ( data ) => {
trösta. logga ( 'Mottagna data:' , data. att stränga ( ) ) ;
} ) ;
} ) ;
server. ( 'stänga' , ( ) => {
trösta. logga ( 'Server stängd' ) ;
} ) ;
konst hamn = 3000 ;
server. lyssna ( hamn, ( ) => {
trösta. logga ( `Server lyssnar på port $ { hamn } ` ) ;
} ) ;
setTimeout ( ( ) => {
trösta. logga ( 'Stänger server efter 10 sekunder' ) ;
server. stänga ( ) ;
bearbeta. utgång ( ) ;
} , 10 000 ) ;

I denna kod:

  • ' const net = require('net') ' importerar den nätmodul som krävs för att hantera en TCP-server och ' const server = net.createServer((socket) => { ” skapar en ny TCP-serverinstans.
  • ' socket.on(‘stäng’, () => {... } ” lyssnar på ”stäng” på alla uttag. När uttaget stängs loggas meddelandet 'Socket Closed' till terminalen.
  • ' socket.on(‘data’, (data) => {} ” söker efter inkommande data från alla individuella sockets och skriver ut dem med funktionen ”.toString()”.
  • ' server.on('stäng', () => {...} ” söker efter händelsen ”stäng” på själva servern, och när serveranslutningen stängs loggas meddelandet ”Server stängd” till terminalen.
  • ' server.listen(port, () => {...} ” lyssnar på inkommande anslutningar på porten.
  • ' setTimeout(() => {…} ” ställer in en timer på 10 ms för att stänga servern.

Därmed avslutas diskussionen om de olika faserna av evenemangsslingan i Node.js. Innan vi drar till en slutsats låt oss diskutera en sista sak som är hur man lämnar händelseslingan i Node.js.

Avsluta Event Loop i Node.js

Händelseloopen är i exekveringsfasen så länge det finns några uppgifter i alla köer av händelseloopfaser. Händelseloopen slutar efter att utgångsfasen har sänts ut och utgångslyssnarens återuppringning återkommer om inga fler uppgifter finns i köerna.

Det explicita sättet att avsluta en händelseslinga är att använda metoden '.exit'. De aktiva processerna för Node.js kommer att avslutas omedelbart så snart process.exit-funktionen anropas. Alla schemalagda och väntande händelser kommer att tas bort:

bearbeta. ( 'utgång' , ( koda ) => {

trösta. logga ( `Avsluta med utgångskod : $ { koda } ` ) ;

} ) ;

bearbeta. utgång ( 1 ) ;

Användare kan lyssna på .exit-funktionen. Det bör noteras att '.exit'-funktionen måste vara synkron eftersom Node.js-programmet avslutas så snart det lyssnar på denna händelse.

Detta avslutar diskussionen om evenemangsslingan. En djupgående artikel som har täckt alla koncept, faser och exempel relaterade till evenemangsslingan.

Slutsats

Innan du förstår händelseslingan kan en översikt över de synkrona och asynkrona koncepten hjälpa till att förstå kodflödet i händelseslingan. Synkron exekvering innebär steg-för-steg exekvering medan asynkron exekvering innebär att vissa steg stoppas utan att vänta på att de är slutförda. Hur evenemangsslingan fungerar tillsammans med alla faser tillsammans med lämpliga exempel diskuteras i artikeln.