03/28/2024

Cum funcționează bucla de evenimente în JavaScript?

Deși ar putea necesita o înțelegere aprofundată a limbajelor precum C++ și C pentru a scrie cod de producție la scară largă, JavaScript poate fi adesea scris doar cu o înțelegere de bază a ceea ce se poate face cu limbajul.

Conceptele, cum ar fi transmiterea apelurilor înapoi la funcții sau scrierea codului asincron, nu sunt adesea atât de dificil de implementat, ceea ce face ca majoritatea dezvoltatorilor JavaScript să nu le pese mai puțin de ceea ce se întâmplă sub capotă. Pur și simplu nu le pasă să înțeleagă complexitățile care s-au abstras profund din ele de către limbaj.

În calitate de dezvoltator JavaScript, devine din ce în ce mai important să înțelegem ce se întâmplă cu adevărat sub capotă și cum funcționează cu adevărat majoritatea acestor complexități abstracte de la noi. Ne ajută să luăm decizii mai informate, care, la rândul lor, pot crește drastic performanța codului nostru.

Acest articol se concentrează pe unul dintre conceptele sau termenii foarte importanți, dar rar înțeleși din JavaScript. BUCLA DE EVENIMENT!.

Scrierea codului asincron nu poate fi evitată în JavaScript, dar de ce înseamnă cu adevărat un cod care rulează asincron? adică The Event Loop

Înainte de a înțelege cum funcționează bucla de evenimente, mai întâi trebuie să înțelegem ce este JavaScript în sine și cum funcționează!

Ce este JavaScript?

Înainte de a continua, aș dori să facem un pas înapoi la elementele de bază. Ce este de fapt JavaScript? Am putea defini JavaScript ca;

JavaScript este un limbaj de nivel înalt, interpretat, fără blocare, asincron, cu un singur thread.

Stai, ce-i asta? O definiție livrescă? 🤔

Haideți să o descompunem!

Cuvintele cheie de aici în ceea ce privește acest articol sunt cu un singur fir, neblocante, concurente și asincrone.

Un singur fir

Un fir de execuție este cea mai mică secvență de instrucțiuni programate care poate fi gestionată independent de un planificator. Un limbaj de programare este cu un singur thread, înseamnă că poate efectua o singură sarcină sau operație la un moment dat. Aceasta înseamnă că ar executa un întreg proces de la început până la sfârșit, fără ca firul să fie întrerupt sau oprit.

Spre deosebire de limbile cu mai multe fire de execuție, în care mai multe procese pot fi rulate pe mai multe fire simultan, fără a se bloca reciproc.

Cum poate JavaScript să fie cu un singur thread și fără blocare în același timp?

  Ce este inclus într-o verificare a antecedentelor?

Dar ce înseamnă blocarea?

Neblocare

Nu există o singură definiție a blocării; înseamnă pur și simplu lucruri care rulează încet pe fir. Deci non-blocare înseamnă lucruri care nu sunt lente pe fir.

Dar stai, am spus că JavaScript rulează pe un singur fir? Și am mai spus că nu se blochează, ceea ce înseamnă că sarcina rulează rapid pe stiva de apeluri? Dar cum??? Ce zici când rulăm cronometre? Bucle?

Relaxa! Am afla peste putin 😉.

Concurente

Concurența înseamnă că codul este executat simultan de mai multe fire.

Bine, lucrurile devin cu adevărat ciudat acum, cum poate JavaScript să fie cu un singur thread și să fie concurent în același timp? adică executarea codului său cu mai mult de un fir?

Asincron

Programarea asincronă înseamnă că codul rulează într-o buclă de evenimente. Când există o operațiune de blocare, evenimentul este pornit. Codul de blocare continuă să ruleze fără a bloca firul de execuție principal. Când codul de blocare se termină de rulat, acesta este rezultatul operațiunilor de blocare și le împinge înapoi în stivă.

Dar JavaScript are un singur fir? Apoi, ce execută acest cod de blocare în timp ce lasă alte coduri din fir să fie executate?

Înainte de a continua, să facem o recapitulare a celor de mai sus.

  • JavaScript este cu un singur thread
  • JavaScript este neblocant, adică procesele lente nu blochează execuția acestuia
  • JavaScript este concurent, adică își execută codul în mai multe fire în același timp
  • JavaScript este asincron, adică rulează cod de blocare în altă parte.

Dar cele de mai sus nu se adună exact, cum poate un limbaj cu un singur thread să fie neblocant, concurent și asincron?

Să mergem puțin mai adânc, să mergem la motoarele JavaScript runtime, V8, poate că are câteva fire ascunse despre care nu suntem conștienți.

Motor V8

Motorul V8 este un motor de execuție de asamblare web open-source de înaltă performanță pentru JavaScript, scris în C++ de Google. Cele mai multe browsere rulează JavaScript folosind motorul V8 și chiar și popularul mediu de rulare node js îl folosește și el.

În limba engleză simplă, V8 este un program C++, care primește cod JavaScript, îl compilează și îl execută.

V8 face două lucruri majore;

  • Alocarea memoriei heap
  • Contextul de execuție a stivei de apeluri

Din păcate, suspiciunea noastră a fost greșită. V8 are doar o singură stivă de apeluri, gândiți-vă la stiva de apeluri ca fiind firul.

Un fir === o stivă de apeluri === o execuție la un moment dat.

  Cum să adăugați ramificații în Microsoft Forms

Imagine – Hacker Noon

Deoarece V8 are doar o singură stivă de apeluri, cum rulează JavaScript concomitent și asincron fără a bloca firul de execuție principal?

Să încercăm să aflăm scriind un cod asincron simplu, dar comun și să-l analizăm împreună.

JavaScript rulează fiecare cod linie cu linie, unul după altul (cu un singur fir). După cum era de așteptat, prima linie este tipărită în consolă aici, dar de ce este tipărită ultima linie înainte de codul de timeout? De ce procesul de execuție nu așteaptă codul de timeout (blocare) înainte de a continua să ruleze ultima linie?

Un alt thread pare să ne fi ajutat să executăm acel timeout, deoarece suntem destul de siguri că un fir poate executa doar o singură sarcină în orice moment.

Să aruncăm o scurtă privire în Cod sursă V8 pentru o vreme.

Stai ce??!!! Nu există funcții de cronometru în V8, nu există DOM? Niciun eveniment? Fără AJAX?… Yeeeessss!!!

Evenimentele, DOM, temporizatoarele etc. nu fac parte din implementarea de bază a JavaScript, JavaScript se conformează strict cu specificațiile Ecma Scripts și diferite versiuni ale acestuia sunt adesea menționate conform specificațiilor sale Ecma Scripts (ES X).

Flux de lucru de execuție

Evenimentele, temporizatoarele, solicitările Ajax sunt toate furnizate pe partea client de către browsere și sunt adesea denumite Web API. Acestea sunt cele care permit JavaScript-ului cu un singur thread să fie neblocant, concurent și asincron! Dar cum?

Există trei secțiuni majore pentru fluxul de lucru de execuție al oricărui program JavaScript, stiva de apeluri, API-ul web și coada de activități.

Stiva de apeluri

O stivă este o structură de date în care ultimul element adăugat este întotdeauna primul care este scos din stivă, l-ați putea gândi ca la o stivă de plăci în care numai prima placă care a fost adăugată ultima poate fi îndepărtată prima. O stivă de apeluri nu este pur și simplu altceva decât o structură de date stivă în care sarcinile sau codul sunt executate în consecință.

Să luăm în considerare exemplul de mai jos;

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

Când apelați funcția printSquare() , aceasta este împinsă în stiva de apeluri, funcția printSquare() apelează funcția square(). Funcția square() este împinsă în stivă și apelează, de asemenea, funcția multiplicare(). Funcția de multiplicare este împinsă pe stivă. Deoarece funcția de multiplicare revine și este ultimul lucru care a fost împins în stivă, se rezolvă mai întâi și este eliminată din stivă, urmată de funcția square() și apoi de funcția printSquare().

API-ul web

Aici este executat codul care nu este gestionat de motorul V8 pentru a nu „bloca” firul de execuție principal. Când stiva de apeluri întâlnește o funcție API web, procesul este imediat transmis API-ului web, unde este executat și eliberând stiva de apeluri să efectueze alte operațiuni în timpul execuției sale.

  Cum să activați noul design Gmail

Să revenim la exemplul nostru setTimeout de mai sus;

Când rulăm codul, prima linie console.log este împinsă în stivă și obținem rezultatul aproape imediat, când ajungem la timeout, cronometrele sunt gestionate de browser și nu fac parte din implementarea de bază a lui V8, este împins. în schimb, la API-ul Web, eliberând stiva astfel încât să poată efectua alte operațiuni.

În timp ce timeout-ul încă rulează, stiva trece la următoarea linie de acțiune și rulează ultimul console.log, ceea ce explică de ce îl obținem înainte de ieșirea temporizatorului. Odată ce cronometrul este finalizat, se întâmplă ceva. Consola.log in apoi timer-ul apare magic din nou în stiva de apeluri!

Cum?

Bucla evenimentului

Înainte de a discuta bucla de evenimente, să trecem mai întâi prin funcția cozii de sarcini.

Revenind la exemplul nostru de expirare, odată ce API-ul web termină de executat sarcina, nu o împinge automat înapoi în stiva de apeluri. Se duce la Task Queue.

O coadă este o structură de date care funcționează pe principiul First in First out, astfel încât sarcinile sunt împinse în coadă, acestea ies în aceeași ordine. Activitățile care au fost executate de API-urile web, care sunt împinse în coada de activități, apoi merg înapoi la stiva de apeluri pentru a-și imprima rezultatul.

Dar asteapta. CE naiba este bucla de evenimente???

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

Bucla de evenimente este un proces care așteaptă ca stiva de apeluri să fie clară înainte de a împinge apelurile înapoi din coada de activități în stiva de apeluri. Odată ce stiva este clară, bucla de evenimente se declanșează și verifică Coada de sarcini pentru apeluri disponibile. Dacă există, îl împinge în stiva de apeluri, așteaptă ca stiva de apeluri să fie eliminată din nou și repetă același proces.

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

Diagrama de mai sus demonstrează fluxul de lucru de bază dintre bucla de evenimente și coada de activități.

Concluzie

Deși aceasta este o introducere foarte simplă, conceptul de programare asincronă în JavaScript oferă suficientă perspectivă pentru a înțelege clar ce se întâmplă sub capotă și modul în care JavaScript este capabil să ruleze simultan și asincron cu un singur fir.

JavaScript este întotdeauna la cerere și, dacă sunteți curios să învățați, vă sfătuiesc să verificați acest lucru curs Udemy.

x