Node.js event loop
@JoshDeveloperEvent loop - "node.js"ni tushunishimiz uchun eng muhim aspektlardan biri va ''interview''larda ham eng ko'p so'raladigan savollardan hisoblanadi. Nima sababdan u bunchalik muhim? Chunki node.jsda asinxronlik, bloklanmaydigan kirish-chiqish so'rovlariga node.js aynan event loop orqali erishadi.
Ma'lumot uchun: "event loop" - bu "node.js"ning C tilida yozilgan "libuv" kutubxonasida joylashgan va uning markaziy qismlaridan hisoblanadi. Bu kutubxona "node.js"da bloklanmaydigan kirish-chiqish so'rovlari (non-blocking I/O)ni ta'minlab beradi. Browserlarda ham "event loop" mavjud va u har bir "tab"da alohida ishlaydi. Bu browserni to'liq to'xtatib qo'ymasligi uchun.
Bilamizki, JavaScript - bu "single-threaded" til hisoblanadi. Ya'ni, 1 vaqtda faqat 1 dona ish bajariladi va bu juda qo'l keladi. Chunki dasturchidan bu borada sodir bo'ladigan xatolilkarni o'ylash talab qilinmaydi.
Dasturchi faqatgina kodni qanday yozishiga e'tibor berishi va so'rovni bloklab qo'yishi mumkin bo'lgan koddan ehtiyot bo'lishi so'raladi (masalan: "infinite loop" ya'ni cheksiz loop).
Event loopni bloklab qo'yish
Javob qaytishi uchun ko'proq vaqt talab qiladigan har qanday JavaScript kodi "event loop"ni bloklab qo'yadi, hattoki "UI" chaqiruvini ham bloklaydi va foydalanuvchi turgan betidan hech qaysi tugma (button)ni ham bosolmaydi, "scroll" ham qilolmaydi.
JavaScriptda deyarli har qanday kirish-chiqish (input-output, qisqartmasi I/O) so'rovlari bloklanmaydi, masalan http so'rovlar, "file system (fs)"ga murojaat va hokazo. Ya'ni, ulardan javob kutmaydi va keyingi qatorga o'tib ketaveradi. Ulardan javob qanday olinadi? Aynan shuning uchun ham JavaScriptda callback, promise va async/await lardan faol foydalaniladi.
Ma'lumot: sanab o'tilgan 3 narsa - callback, promise va async/await bitta vazifani bajaradi. callbacklardan ichma-ich foydalanishga to'g'ri kelganda kod juda tushunarsiz va "debug" qilish uchun qiyin bo'lgan va bu "callback hell" deya dasturchilar orasida nom olgan. "callback hell"ni oldini olish uchun JavaScriptning 2015-yildagi ya'ni ES6 yangilanishida Promiselar kiritilgan. Bu aynan o'ylangan narsa, "callback hell"ni oldini olgan, lekin boshqa bir muommo keltirib chiqargan: sintaksis murakkab. Va bu oxirgi yechim emasligini barcha tushungan. 2016-yildagi yangilanish ya'ni ES7 da anchagina sodda, ko'pgina muommolarni hal qiladigan, promiselar ustiga qurilgan async/await sintaksisi kiritiladi va javascript tarixidagi eng muhim versiyalardan biriga aylanadi.
P.s: Bu degani promise va callbacklardan to'liq voz kechildi degani emas va har biri haqida alohida chiqarilgan va endi chiqariladigan maqolalarimizdan o'qishingiz mumkin.
Call stack
JavaScript kodlarni qatorma-qator o'qiydi va chaqirilishi kerak bo'lgan kodlarni "call stack"ga joylab boradi. Call stack - LIFO ya'ni "last in, first out" - birinchi turgani chaqiriladi, yangi qo'shilgani oxiriga qo'shiladi. Poleklenikadagi navbatni tasavvur qilishingiz mumkin. (Eslab qoling!)
Event loop call stackni davomli ravishda tekshirib turadi.
Browser "console"idagi "error stack trace"ni bilsangiz kerak. Browser ayni damdagi chaqiruv qaysi funksiyaga tegishli ekanligini bilishlik uchun call stackga qaraydi:

Event loopni oddiyroq tushunturish
Oddiyroq kod yozaylik:

Xo'sh, bu kod qay tartibda ishlaydi? Albatta bu qiyin savol emas: avval "foo" funksiyasi chaqiriladi va uning ichidagi kodlar chaqirilishni boshlaydi: avval "foo" consolega yoziladi, bar funksiyasi chaqirilib, uning ichidagi kod chaqiriladi, ya'ni "bar" consolega yoziladi, undan keyin baz funksiyasi chaqirilib uning ichidagi console.log('baz') ishlaydi va kod chaqirilishi tugaydi.
Bunda call stackda quyidagicha jarayon ro'y beradi:

Event loop esa har bir aylanganda call stackda biror nima bormi deya tekshiradi va kod bo'lsa, uni chaqiradi (call stack bo'shagunga qadar):

Funksiya chaqiruvi navbati
Yuqoridagi kod normal kod, JavaScript ularni qatorma-qator chaqiradi.
Endi keling call stackni bo'shashini "kechiktirish"ni ko'rib chiqaylik:
setTimeout(() => { bizningKodimiz }, 0) (e'tibor qiling, nol sekunddan keyin deyilyapti) call stackdagi barcha funksiyalar chaqirilganidan keyin, "setTimeout" ichidagi kod chaqirilishi aytilyapti.

Bu kod beradigan javob hayratlanarli bo'lib ko'rinishi mumkin:
foo
baz
bar
Nimalar bo'lyapti deb o'ylayotgan bo'lsangiz, shu savolga javob topish uchun ketma-ketlikni ko'rib chiqaylik: avvaliga foo() funksiyasi chaqirilyapti, ichidagi birinchi kod, "foo" consolega yozilyapti, undan keyin setTimeout(() => console.log('bar')) funksiyasi chaqirilyapti va bu funksiyani ko'rganda JavaScript undan javob kutib o'tirmaydi, uni ichki 'api'lardan bo'lgan "timer api"ga jo'natadi va keyingi qatorga o'tadi. Keyingi qatordagi koddan "baz"ni consolega chiqaradi. Ayni jarayonda "timer api" sanoqni boshlagan bo'ladi va sanoq tugagach (bizning misolimizda darhol) uni navbatga (oxirgi bo'lib) qo'shib qo'yadi. (bu haqida keyingi paragrafda yozilgan)
Bu paytda call stackning ko'rinishi:

Va event loop har bir iteratsiyasida nima amal bajarilishi:

The message queue
Hozirgina aytib o'tganimdagidek, qachonki setTimeout() funksiyasi chaqirilganda browser yoki node.js sanoqni boshlaydi va undagi 'callback'ni "message queue"ga qo'shib qo'yadi.
"Message queue", shuningdek foydalanuvchiga bog'langan harakat, masalan "button" bosilishi kabilarni ham toki kodimiz ularga javob berishga imkon topmaguncha navbatda saqlanadi. (onLoad kabi DOM 'event'lari ham).
Event loop - call stackdagi kodlarni avvalidan boshlab chaqiradi va u yerda hech nima qolmagach, "message queue"dagi kodlarni navbat bilan chaqirishni boshlaydi.
Biz setTimeout(), http so'rovlari... kabilarni kutib turishimiz shart emas, ular o'zining alohida "thread"ida yashaydi. Ya'ni masalan bizning misoldagi setTimeout() boshqa bir joyda sanoqni bajaradi, uni 2 sekundga qo'ysak, 'bar' va keyin 'baz' yozilishini 2 sekund kutishimiz shart emas, bu vaqt boshqa bir joyda kutiladi va u tugagach, navbatga qo'shib qo'yiladi. Navbatga qo'shilgan kod esa ayni damdagi yurib turgandan keyin qaraladi, shuning uchun ham avval 'baz' va keyin, message queuedagi 'bar' consolega chiqarilyapti
ES6 job queue
Men yuqorida bekorga poleklenikadagi navbatni misol qilmadim.
JavaScriptning ES6 versiyasida promiselar foydalanadigan "job queue" ham tanishtirildi. Ya'ni "bu mening xolam" deb navbatda birinchi bo'lib turib olishni mana shu navbatda ham ko'rishimiz mumkin.
"Job queue" shunday dizaynlashtirilganki, e'tibor asinxron funksiyani eng oxirgi bo'lib emas, iloji boricha tezroq chaqirishga qaratilgan. Ya'ni ''message queue''dagi kodlardan oldin ''job queue''dagi kodlar chaqiriladi:

Natija:
foo
baz
should be righ after baz, before bar
bar
Bu kod chaqirilish jarayonidagi call stack (ko'chirib olib yaqinlashtirib ko'rishingiz mumkin):

Callback, promise va async/await haqidagi maqolalarni kanalimizda o'qishingiz mumkin.