Runtime-ul Javascript este cu un singur fir, ceea ce înseamnă că poate executa o bucată de cod la un moment dat. Pentru a înțelege modelul concurenței și bucla de evenimente în Javascript, trebuie mai întâi să cunoaștem câțiva termeni comuni care sunt asociați cu acesta.

Stiva de apeluri

Mai întâi să învățăm despre ce este o stivă de apeluri.

O stivă de apeluri este o structură simplă de date care înregistrează unde suntem în cod. Deci, dacă intrăm într-o funcție care este o invocație de funcție, aceasta este împinsă în stiva de apeluri. Când ne întoarcem dintr-o funcție, este scoasă din stivă.

Să vedem un exemplu de cod pentru a înțelege stiva de apeluri:

function multiply(x,y) {
   return x * y;
}

function squared(n) {
     return multiply(n,n)
  }

function printSquare(n) {
   return squared(n)
}

let numberSquared = printSquare(5);
console.log(numberSquared);

Mai întâi când se execută codul, runtime-ul va citi fiecare definiție a funcției. Dar când ajunge la linia unde se află prima funcție printSquare (5) este invocat va împinge această funcție în stiva de apeluri.

Apoi, această funcție se va executa. Înainte de a reveni, va întâlni o altă funcție, pătrat (n), deci își va suspenda funcționarea curentă și va împinge această funcție deasupra funcției existente.

Execută funcția (în acest caz funcția pătrată) și, în cele din urmă, întâlnește o altă funcție multiplica (n, n). Apoi își suspendă execuțiile curente și împinge această funcție în stiva de apeluri. Funcția multiply se execută și revine cu valoarea multiplicată.

În cele din urmă, funcția pătrată revine și este scoasă din stivă și apoi același lucru este valabil și cu printSquare. Valoarea pătrată finală este alocată variabilei NumberSquared.

Ne întâlnim din nou cu o invocare a funcției (în acest caz este o instrucțiune console.log ()), astfel încât timpul de rulare îl împinge pe stivă. Aceasta îl execută imprimând astfel numărul pătrat pe consolă.

Rețineți că prima funcție care este împinsă în stivă înainte ca oricare dintre codurile de mai sus să ruleze este funcția principală. În timpul rulării, aceasta este denumită „funcție anonimă”.

Deci, pentru a rezuma: ori de câte ori este invocată o funcție, aceasta este împinsă în stiva de apeluri unde se execută. În cele din urmă, când funcția este realizată cu executarea ei și se întoarce fie implicit, fie în mod explicit, aceasta va fi scoasă din stivă.

Stiva de apeluri înregistrează doar în ce moment din timp funcția a fost executată. Și ține evidența funcției care se execută în prezent.

Browserul

Acum știm din aceasta că Javascript poate executa câte un lucru la un moment dat, dar nu este cazul browserului. Browser-ul are propriul set de API-uri precum setTimeout și XMLHttpRequests care nu sunt specificate în runtime-ul Javascript.

De fapt, dacă căutați codul sursă al V8, popularul timp de rulare Javascript care alimentează browsere precum Google Chrome, nu veți găsi definiții pentru acesta. Acest lucru se datorează faptului că aceste API-uri web speciale există în mediul browserului, nu în mediul javascript. Deci, puteți spune că aceste API-uri introduc concurență în mix.

Să ne uităm la o diagramă pentru a înțelege întreaga imagine.

Model de buclă de concurență și eveniment

Mai sunt introduși câțiva termeni aici, deci să le parcurgem:

Morman: Este în mare parte locul în care sunt alocate obiecte.

Coadă de apel invers: Este o structură de date care stochează toate apelurile de apel. Deoarece este o coadă, elementele sunt procesate pe baza FIFO, care este First in First Out.

Bucla eveniment: Aici se întâlnesc toate aceste lucruri. Bucla de evenimente verifică pur și simplu stiva de apeluri, iar dacă este goală (ceea ce înseamnă că nu există funcții în stivă) preia cea mai veche apelare din coada de apelare inversă și o împinge în stiva de apelare care, în cele din urmă, execută apelarea inversă.

Să înțelegem acest lucru cu un exemplu de cod:

console.log('hi');

setTimeout(function() {
     console.log('freecodeCamp')
},5000);

console.log('JS')

Când prima linie se execută este console.log (). Aceasta este o invocare a funcției, ceea ce înseamnă că această funcție este împinsă în stiva de apeluri unde execută tipărirea „hi” pe consolă. În cele din urmă este returnat și este scos din stivă.

Apoi, când runtime-ul se execută setTimeout (), știe că acesta este un API web. Prin urmare, îl dă browserului pentru a gestiona execuția acestuia. Browserul pornește cronometrul și apoi JS runtime scoate setTimeout () din stivă. Se întâlnește cu o altă invocație console.log () și, prin urmare, împinge aceasta în stiva de apeluri, mesajul „JS” este conectat în consolă și apoi este returnat în cele din urmă. Apoi ultima console.log () este scoasă din stivă. Acum stiva de apeluri este goală.

Între timp, în timp ce toate acestea se întâmplau, cronometrul se termină. După ce au trecut 5 secunde, browserul continuă și împinge funcția de apel invers în coada de apel invers.

Apoi bucla de evenimente verifică dacă stiva de apeluri este gratuită sau nu. Deoarece este gratuit, preia funcția de apel invers și o împinge din nou în teancul de apeluri care execută codul din interior.

Din nou în interiorul codului există o invocație console.log (), astfel încât această funcție merge în partea de sus a stivei execută care înregistrează „freecodecamp” în consolă și în cele din urmă se întoarce. Acest lucru înseamnă că se scoate din stivă și, în cele din urmă, callback-ul se stinge din stivă și am terminat.

Pentru a vizualiza mai bine acest lucru, încercați acest instrument de Phillip Roberts: Vizualizator Loop Event Loop