Kā notikumu cilpa darbojas JavaScript?

Lai gan, lai rakstītu pilna mēroga ražošanas kodu, var būt nepieciešama padziļināta izpratne par tādām valodām kā C++ un C, JavaScript bieži var rakstīt tikai ar pamata izpratni par to, ko var darīt ar šo valodu.

Jēdzieni, piemēram, atzvanīšanas nodošana funkcijām vai asinhrona koda rakstīšana, bieži vien nav tik grūti īstenojami, tāpēc lielākajai daļai JavaScript izstrādātāju ir mazāk rūp tas, kas notiek zem pārsega. Viņiem vienkārši nav svarīgi saprast sarežģījumus, ko valoda viņiem ir dziļi abstrahējusi.

Kā JavaScript izstrādātājam kļūst arvien svarīgāk izprast, kas patiesībā notiek zem pārsega un kā patiesībā darbojas lielākā daļa no mums iegūtajām sarežģītībām. Tas palīdz mums pieņemt pārdomātākus lēmumus, kas savukārt var ievērojami uzlabot mūsu koda veiktspēju.

Šajā rakstā uzmanība tiek pievērsta vienam no ļoti svarīgajiem, bet reti saprotamiem jēdzieniem vai terminiem JavaScript. PASĀKUMU CILPA!.

JavaScript nevar izvairīties no asinhrona koda rakstīšanas, bet kāpēc kods, kas darbojas asinhroni, patiesībā nozīmē? ti, notikumu cilpa

Lai mēs varētu saprast, kā darbojas notikumu cilpa, mums vispirms ir jāsaprot, kas ir pats JavaScript un kā tas darbojas!

Kas ir JavaScript?

Pirms mēs turpinām, es vēlētos, lai mēs atgriežamies pie pašiem pamatiem. Kas īsti ir JavaScript? Mēs varētu definēt JavaScript kā;

JavaScript ir augsta līmeņa, interpretēta, viena pavediena nebloķējoša, asinhrona, vienlaicīga valoda.

Pagaidiet, kas tas ir? Grāmatiska definīcija? 🤔

Izjauksim to!

Atslēgvārdi šeit attiecībā uz šo rakstu ir viens pavediens, nebloķējošs, vienlaikus un asinhrons.

Viens pavediens

Izpildes pavediens ir mazākā ieprogrammēto instrukciju secība, ko plānotājs var pārvaldīt neatkarīgi. Programmēšanas valoda ir viena pavediena, kas nozīmē, ka tā var veikt tikai vienu uzdevumu vai darbību vienā reizē. Tas nozīmē, ka tas izpildītu visu procesu no sākuma līdz beigām, nepārtraucot vai neapturot pavedienu.

Atšķirībā no vairāku pavedienu valodām, kurās vairākus procesus var palaist vairākos pavedienos vienlaikus, viens otru nebloķējot.

Kā JavaScript var vienlaikus būt ar vienu pavedienu un nebloķēt?

Bet ko nozīmē bloķēšana?

Nebloķējošs

Nav vienas bloķēšanas definīcijas; tas vienkārši nozīmē lietas, kas pa pavedienu darbojas lēni. Tātad nebloķēšana nozīmē lietas, kas pavedienā nav lēnas.

  14 labākās PDF meklētājprogrammas, lai atrastu bezmaksas e-grāmatas 2022. gadā

Bet pagaidiet, vai es teicu, ka JavaScript darbojas vienā pavedienā? Un es arī teicu, ka tas nebloķē, kas nozīmē, ka uzdevums tiek ātri izpildīts zvanu stekā? Bet kā??? Kā būtu ar taimeri? Cilpas?

Atpūties! Mēs to uzzināsim pēc brīža 😉.

Vienlaicīgi

Vienlaicība nozīmē, ka kodu vienlaikus izpilda vairāk nekā viens pavediens.

Labi, lietas patiešām kļūst dīvaini tagad, kā JavaScript var būt viena pavediena un vienlaikus vienlaikus? ti, tā koda izpilde ar vairāk nekā vienu pavedienu?

Asinhrons

Asinhronā programmēšana nozīmē, ka kods darbojas notikumu cilpā. Kad tiek veikta bloķēšanas darbība, pasākums tiek sākts. Bloķēšanas kods turpina darboties, nebloķējot galveno izpildes pavedienu. Kad bloķēšanas kods beidz darboties, tas tiek ievietots rindā bloķēšanas darbību rezultātā un nospiež tos atpakaļ uz steku.

Bet JavaScript ir viens pavediens? Kas tad izpilda šo bloķējošo kodu, vienlaikus ļaujot izpildīt citus pavediena kodus?

Pirms turpinām, apkoposim iepriekš minēto.

  • JavaScript ir viens pavediens
  • JavaScript nebloķē, ti, lēni procesi nebloķē tā izpildi
  • JavaScript ir paralēls, ti, tas vienlaikus izpilda savu kodu vairākos pavedienos
  • JavaScript ir asinhrons, ti, tas palaiž bloķējošo kodu kaut kur citur.

Bet iepriekšminētais precīzi neatbilst. Kā viena pavediena valoda var būt nebloķējoša, vienlaicīga un asinhrona?

Padziļināsimies, pievērsīsimies JavaScript izpildlaika dzinējiem, V8, iespējams, tajā ir daži slēpti pavedieni, par kuriem mēs nezinām.

V8 dzinējs

V8 dzinējs ir augstas veiktspējas atvērtā koda tīmekļa montāžas izpildlaika dzinējs JavaScript, ko Google rakstījis C++ valodā. Lielākā daļa pārlūkprogrammu palaiž JavaScript, izmantojot V8 dzinēju, un pat populārā node js izpildlaika vide to izmanto arī.

Vienkāršā angļu valodā V8 ir C++ programma, kas saņem JavaScript kodu, kompilē un izpilda to.

V8 veic divas galvenās lietas;

  • Kaudzes atmiņas piešķiršana
  • Izsaukuma steka izpildes konteksts

Diemžēl mūsu aizdomas bija nepareizas. V8 ir tikai viens zvanu steks, domājiet par zvanu steku kā pavedienu.

Viens pavediens === viens izsaukuma steks === viena izpilde vienlaikus.

Attēls – Hacker Noon

Tā kā V8 ir tikai viens izsaukumu steks, kā tad JavaScript darbojas vienlaicīgi un asinhroni, nebloķējot galveno izpildes pavedienu?

  Kā atrast un dzēst ekrānuzņēmumus pakalpojumā Google fotoattēli

Mēģināsim to noskaidrot, uzrakstot vienkāršu, bet izplatītu asinhrono kodu, un analizēsim to kopā.

JavaScript izpilda katru kodu pēc rindas, vienu pēc otra (vienpavedienu). Kā gaidīts, pirmā rindiņa tiek izdrukāta konsolē šeit, bet kāpēc pēdējā rindiņa tiek drukāta pirms taimauta koda? Kāpēc izpildes process nesagaida taimauta kodu (bloķēšanu), pirms tiek izpildīta pēdējā rindiņa?

Šķiet, ka kāds cits pavediens mums ir palīdzējis izpildīt šo taimautu, jo esam diezgan pārliecināti, ka pavediens jebkurā brīdī var izpildīt tikai vienu uzdevumu.

Ielūkosimies vietnē V8 pirmkods kādu brīdi.

Pagaidi, ko??!!! Vai V8 nav taimera funkciju, nav DOM? Nav notikumu? Nav AJAX?… Eeeeeesss!!!

Notikumi, DOM, taimeri u.c. nav JavaScript galvenās ieviešanas daļa, JavaScript stingri atbilst Ecma skriptu specifikācijām, un dažādas tā versijas bieži tiek apzīmētas saskaņā ar tā Ecma skriptu specifikācijām (ES X).

Izpildes darbplūsma

Notikumus, taimerus un Ajax pieprasījumus nodrošina pārlūkprogrammas klienta pusē, un tos bieži dēvē par Web API. Tie ir tie, kas ļauj viena pavediena JavaScript būt nebloķējošam, vienlaicīgam un asinhronam! Bet kā?

Jebkuras JavaScript programmas izpildes darbplūsmai ir trīs galvenās sadaļas, zvanu steka, tīmekļa API un uzdevumu rinda.

Zvanu kaudze

Kopa ir datu struktūra, kurā pēdējais pievienotais elements vienmēr ir pirmais, kas tiek noņemts no kaudzes. Jūs to varētu uzskatīt par plāksnes kaudzi, kurā vispirms var noņemt tikai pirmo plāksni, kas tika pievienota pēdējā. Call Stack vienkārši nav nekas cits kā steka datu struktūra, kurā attiecīgi tiek izpildīti uzdevumi vai kods.

Apskatīsim tālāk sniegto piemēru;

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

Izsaucot funkciju printSquare() , tā tiek nospiesta uz izsaukuma kaudzi, funkcija printSquare() izsauc square() funkciju. Funkcija kvadrāts () tiek nospiesta uz kaudzi un izsauc arī funkciju reizināt (). Reizināšanas funkcija tiek uzspiesta uz kaudzes. Tā kā reizināšanas funkcija atgriežas un ir pēdējā lieta, kas tika nosūtīta uz steku, tā vispirms tiek atrisināta un tiek noņemta no steka, kam seko funkcija square () un pēc tam funkcija printSquare ().

Web API

Šeit tiek izpildīts kods, ko neapstrādā V8 dzinējs, lai “nebloķētu” galveno izpildes pavedienu. Kad Call Stack saskaras ar tīmekļa API funkciju, process nekavējoties tiek nodots Web API, kur tas tiek izpildīts un atbrīvo zvanu steku citu darbību veikšanai tā izpildes laikā.

  Kā atrast perfektu fitnesa izsekotāju, kas atbilst jūsu vajadzībām

Atgriezīsimies pie mūsu setTimeout piemēra iepriekš;

Kad mēs palaižam kodu, pirmā console.log rindiņa tiek novirzīta uz steku, un mēs saņemam savu izvadi gandrīz nekavējoties, kad tiek sasniegts taimauts, taimerus apstrādā pārlūkprogramma, un tie nav daļa no V8 pamata ieviešanas, tā tiek nospiesta. tā vietā uz Web API, atbrīvojot steku, lai tā varētu veikt citas darbības.

Kamēr taimauts joprojām darbojas, steks pāriet uz nākamo darbības līniju un palaiž pēdējo console.log, kas izskaidro, kāpēc tas tiek izvadīts pirms taimera izvades. Kad taimeris ir pabeigts, kaut kas notiek. Console.log in tad taimeris maģiski parādās zvanu kaudzē vēlreiz!

Kā?

Pasākumu cilpa

Pirms mēs apspriežam notikumu cilpu, vispirms apskatīsim uzdevumu rindas funkciju.

Atgriežoties pie mūsu noildzes piemēra, kad Web API pabeidz uzdevuma izpildi, tas ne tikai automātiski nospiež to atpakaļ uz zvanu steku. Tas nonāk uzdevumu rindā.

Rinda ir datu struktūra, kas darbojas pēc principa First in First out, tāpēc, kad uzdevumi tiek ievietoti rindā, tie tiek izvadīti tādā pašā secībā. Tīmekļa API izpildītie uzdevumi, kas tiek novirzīti uz uzdevumu rindu, pēc tam dodas atpakaļ uz zvanu kopu, lai izdrukātu to rezultātus.

Bet pagaidi. KAS IR PASĀKUMA CILPA???

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

Notikumu cilpa ir process, kas gaida, līdz zvanu steks ir skaidrs, pirms tiek pārsūtīti atzvani no uzdevumu rindas uz zvanu kopu. Kad kopa ir notīrīta, notikumu cilpa aktivizē un pārbauda, ​​vai uzdevumu rindā nav pieejami atzvanīšanas gadījumi. Ja tādi ir, tas nospiež to uz zvanu kopu, gaida, līdz zvanu kopa atkal ir notīrīta, un atkārto to pašu procesu.

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

Iepriekš redzamā diagramma parāda pamata darbplūsmu starp notikumu cilpu un uzdevumu rindu.

Secinājums

Lai gan šis ir ļoti vienkāršs ievads, asinhronās programmēšanas jēdziens JavaScript sniedz pietiekamu ieskatu, lai skaidri saprastu, kas notiek zem pārsega un kā JavaScript spēj darboties vienlaikus un asinhroni tikai ar vienu pavedienu.

JavaScript vienmēr ir pēc pieprasījuma, un, ja vēlaties uzzināt, es ieteiktu to pārbaudīt Udemy kurss.