JavaScript Event Loop sirlarini oching, vazifalar navbati ustuvorligi va mikrotasklarni rejalashtirishni tushuning. Har bir global dasturchi uchun zarur bilimlar.
JavaScript Event Loop: Global Dasturchilar uchun Vazifalar Navbati Ustuvorligi va Mikrotasklarni Rejalashtirishni O'zlashtirish
Veb-dasturlash va server ilovalarining dinamik dunyosida JavaScript kodni qanday bajarishini tushunish juda muhimdir. Dunyo bo'ylab dasturchilar uchun JavaScript Event Loop'ni chuqur o'rganish nafaqat foydali, balki samarali, sezgir va bashorat qilinadigan ilovalarni yaratish uchun zarurdir. Ushbu maqola Event Loop'ni tushuntirib, vazifalar navbati ustuvorligi va mikrotasklarni rejalashtirishning muhim tushunchalariga e'tibor qaratadi va turli xalqaro auditoriya uchun amaliy tushunchalarni taqdim etadi.
Asos: JavaScript kodni qanday bajaradi
Event Loop'ning murakkabliklariga sho'ng'ishdan oldin, JavaScript'ning fundamental ijro modelini tushunib olish muhim. An'anaviy ravishda, JavaScript bir oqimli tildir. Bu bir vaqtning o'zida faqat bitta operatsiyani bajarishi mumkinligini anglatadi. Biroq, zamonaviy JavaScript'ning sehrli tomoni shundaki, u asosiy oqimni bloklamasdan asinxron operatsiyalarni bajara oladi, bu esa ilovalarni juda sezgir qiladi.
Bunga quyidagilarning kombinatsiyasi orqali erishiladi:
- The Call Stack (Chaqiruvlar steki): Bu yerda funksiya chaqiruvlari boshqariladi. Funksiya chaqirilganda, u stekning tepasiga qo'shiladi. Funksiya qaytganda, u tepadan olib tashlanadi. Sinxron kodning ijrosi shu yerda sodir bo'ladi.
- The Web APIs (brauzerlarda) yoki C++ APIs (Node.js'da): Bular JavaScript ishlayotgan muhit tomonidan taqdim etiladigan funksionalliklardir (masalan,
setTimeout, DOM hodisalari,fetch). Asinxron operatsiya uchraganda, u ushbu API'larga uzatiladi. - The Callback Queue (Qayta chaqiruv navbati) yoki Task Queue (Vazifalar navbati): Web API tomonidan boshlangan asinxron operatsiya tugagach (masalan, taymer muddati tugaganda, tarmoq so'rovi tugallanganda), unga bog'liq bo'lgan qayta chaqiruv funksiyasi Callback navbatiga joylashtiriladi.
- The Event Loop (Hodisalar tsikli): Bu orkestr dirijori. U doimiy ravishda Call Stack va Callback navbatini kuzatib boradi. Call Stack bo'sh bo'lganda, u Callback navbatidan birinchi qayta chaqiruvni oladi va uni ijro etish uchun Call Stack'ka joylashtiradi.
Ushbu asosiy model setTimeout kabi oddiy asinxron vazifalar qanday bajarilishini tushuntiradi. Biroq, Promise'lar, async/await va boshqa zamonaviy xususiyatlarning joriy etilishi mikrotasklarni o'z ichiga olgan yanada murakkab tizimni keltirib chiqardi.
Mikrotasklar bilan tanishuv: Yuqori ustuvorlik
An'anaviy Callback navbati ko'pincha Makrotasklar navbati yoki oddiygina Vazifalar navbati deb ataladi. Aksincha, Mikrotasklar makrotasklarga qaraganda yuqori ustuvorlikka ega alohida navbatni ifodalaydi. Bu farq asinxron operatsiyalarning aniq ijro tartibini tushunish uchun juda muhimdir.
Mikrotask nimalardan iborat?
- Promise'lar: Promise'larning bajarilishi yoki rad etilishi qayta chaqiruvlari mikrotasklar sifatida rejalashtiriladi. Bunga
.then(),.catch()va.finally()ga uzatilgan qayta chaqiruvlar kiradi. queueMicrotask(): Mikrotasklar navbatiga vazifalarni qo'shish uchun maxsus ishlab chiqilgan mahalliy JavaScript funksiyasi.- Mutation Observers: Ular DOM'dagi o'zgarishlarni kuzatish va qayta chaqiruvlarni asinxron ravishda ishga tushirish uchun ishlatiladi.
process.nextTick()(Node.js'ga xos): Konseptual jihatdan o'xshash bo'lsa-da, Node.js'dagiprocess.nextTick()yanada yuqori ustuvorlikka ega va har qanday I/O (kiritish/chiqarish) qayta chaqiruvlari yoki taymerlardan oldin ishga tushadi va samarali ravishda yuqori darajadagi mikrotask vazifasini bajaradi.
Event Loop'ning takomillashtirilgan tsikli
Event Loop'ning ishlashi Mikrotasklar navbati joriy etilishi bilan yanada murakkablashadi. Takomillashtirilgan tsikl qanday ishlashi quyidagicha:
- Joriy Call Stack'ni bajarish: Event Loop avval Call Stack'ning bo'sh ekanligiga ishonch hosil qiladi.
- Mikrotasklarni qayta ishlash: Call Stack bo'sh bo'lgach, Event Loop Mikrotasklar navbatini tekshiradi. U navbatdagi barcha mikrotasklarni birma-bir, Mikrotasklar navbati bo'sh bo'lguncha bajaradi. Bu eng muhim farq: mikrotasklar har bir makrotask yoki skript ijrosidan so'ng to'plam bilan qayta ishlanadi.
- Render yangilanishlari (Brauzer): Agar JavaScript muhiti brauzer bo'lsa, u mikrotasklarni qayta ishlagandan so'ng render yangilanishlarini amalga oshirishi mumkin.
- Makrotasklarni qayta ishlash: Barcha mikrotasklar tozalangandan so'ng, Event Loop keyingi makrotaskni (masalan, Callback navbatidan,
setTimeoutkabi taymer navbatlaridan, I/O navbatlaridan) tanlaydi va uni Call Stack'ka joylashtiradi. - Takrorlash: Keyin tsikl 1-qadamdan takrorlanadi.
Bu shuni anglatadiki, bitta makrotaskning bajarilishi keyingi makrotask ko'rib chiqilishidan oldin ko'plab mikrotasklarning bajarilishiga olib kelishi mumkin. Bu sezgirlik va ijro tartibiga sezilarli ta'sir ko'rsatishi mumkin.
Vazifalar navbati ustuvorligini tushunish: Amaliy ko'rinish
Keling, turli xil stsenariylarni hisobga olgan holda, butun dunyo dasturchilari uchun dolzarb bo'lgan amaliy misollar bilan ko'rib chiqaylik:
1-misol: `setTimeout` va `Promise` taqqoslanishi
Quyidagi kod parchasini ko'rib chiqing:
console.log('Start');
setTimeout(function callback1() {
console.log('Timeout Callback 1');
}, 0);
Promise.resolve().then(function promiseCallback1() {
console.log('Promise Callback 1');
});
console.log('End');
Sizningcha, natija qanday bo'ladi? London, Nyu-York, Tokio yoki Sidneyda bo'lgan dasturchilar uchun kutilgan natija bir xil bo'lishi kerak:
console.log('Start');darhol bajariladi, chunki u Call Stack'da.setTimeoutuchratiladi. Taymer 0ms ga o'rnatilgan, ammo muhimi shundaki, uning qayta chaqiruv funksiyasi taymer muddati tugagandan so'ng (bu darhol sodir bo'ladi) Makrotasklar navbatiga joylashtiriladi.Promise.resolve().then(...)uchratiladi. Promise darhol bajariladi va uning qayta chaqiruv funksiyasi Mikrotasklar navbatiga joylashtiriladi.console.log('End');darhol bajariladi.
Endi Call Stack bo'sh. Event Loop o'z tsiklini boshlaydi:
- U Mikrotasklar navbatini tekshiradi.
promiseCallback1ni topadi va uni bajaradi. - Mikrotasklar navbati endi bo'sh.
- U Makrotasklar navbatini tekshiradi.
callback1ni (setTimeoutdan) topadi va uni Call Stack'ka joylashtiradi. callback1bajariladi va 'Timeout Callback 1' ni konsolga chiqaradi.
Shuning uchun, natija quyidagicha bo'ladi:
Start
End
Promise Callback 1
Timeout Callback 1
Bu, mikrotasklar (Promise'lar) makrotasklardan (setTimeout) oldin qayta ishlanishini aniq ko'rsatadi, hatto `setTimeout` 0 kechikishga ega bo'lsa ham.
2-misol: Ichma-ich joylashgan asinxron operatsiyalar
Keling, ichma-ich operatsiyalarni o'z ichiga olgan murakkabroq stsenariyni ko'rib chiqaylik:
console.log('Script Start');
setTimeout(() => {
console.log('setTimeout 1');
Promise.resolve().then(() => console.log('Promise 1.1'));
setTimeout(() => console.log('setTimeout 1.1'), 0);
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
setTimeout(() => console.log('setTimeout 2'), 0);
Promise.resolve().then(() => console.log('Promise 1.2'));
});
console.log('Script End');
Keling, ijro jarayonini kuzataylik:
console.log('Script Start');konsolga 'Script Start' ni chiqaradi.- Birinchi
setTimeoutuchratiladi. Uning qayta chaqiruvi (keling, uni `timeout1Callback` deb ataymiz) makrotask sifatida navbatga qo'yiladi. - Birinchi
Promise.resolve().then(...)uchratiladi. Uning qayta chaqiruvi (`promise1Callback`) mikrotask sifatida navbatga qo'yiladi. console.log('Script End');konsolga 'Script End' ni chiqaradi.
Call Stack endi bo'sh. Event Loop ishga tushadi:
Mikrotasklar navbatini qayta ishlash (1-raund):
- Event Loop Mikrotasklar navbatida `promise1Callback` ni topadi.
- `promise1Callback` bajariladi:
- 'Promise 1' konsolga chiqariladi.
setTimeoutga duch keladi. Uning qayta chaqiruvi (`timeout2Callback`) makrotask sifatida navbatga qo'yiladi.- Yana bir
Promise.resolve().then(...)ga duch keladi. Uning qayta chaqiruvi (`promise1.2Callback`) mikrotask sifatida navbatga qo'yiladi. - Mikrotasklar navbati endi `promise1.2Callback` ni o'z ichiga oladi.
- Event Loop mikrotasklarni qayta ishlashni davom ettiradi. U `promise1.2Callback` ni topadi va uni bajaradi.
- Mikrotasklar navbati endi bo'sh.
Makrotasklar navbatini qayta ishlash (1-raund):
- Event Loop Makrotasklar navbatini tekshiradi. `timeout1Callback` ni topadi.
- `timeout1Callback` bajariladi:
- 'setTimeout 1' konsolga chiqariladi.
Promise.resolve().then(...)ga duch keladi. Uning qayta chaqiruvi (`promise1.1Callback`) mikrotask sifatida navbatga qo'yiladi.- Yana bir
setTimeoutga duch keladi. Uning qayta chaqiruvi (`timeout1.1Callback`) makrotask sifatida navbatga qo'yiladi. - Mikrotasklar navbati endi `promise1.1Callback` ni o'z ichiga oladi.
Call Stack yana bo'sh. Event Loop o'z tsiklini qaytadan boshlaydi.
Mikrotasklar navbatini qayta ishlash (2-raund):
- Event Loop Mikrotasklar navbatida `promise1.1Callback` ni topadi va uni bajaradi.
- Mikrotasklar navbati endi bo'sh.
Makrotasklar navbatini qayta ishlash (2-raund):
- Event Loop Makrotasklar navbatini tekshiradi. `timeout2Callback` ni topadi (birinchi setTimeout'ning ichidagi setTimeout'dan).
- `timeout2Callback` bajariladi, 'setTimeout 2' konsolga chiqariladi.
- Makrotasklar navbati endi `timeout1.1Callback` ni o'z ichiga oladi.
Call Stack yana bo'sh. Event Loop o'z tsiklini qaytadan boshlaydi.
Mikrotasklar navbatini qayta ishlash (3-raund):
- Mikrotasklar navbati bo'sh.
Makrotasklar navbatini qayta ishlash (3-raund):
- Event Loop `timeout1.1Callback` ni topadi va uni bajaradi, 'setTimeout 1.1' ni konsolga chiqaradi.
Navbatlar endi bo'sh. Yakuniy natija quyidagicha bo'ladi:
Script Start
Script End
Promise 1
Promise 1.2
setTimeout 1
setTimeout 2
Promise 1.1
setTimeout 1.1
Ushbu misol bitta makrotaskning bir zanjir mikrotasklarni qanday ishga tushirishi mumkinligini va ularning barchasi Event Loop keyingi makrotaskni ko'rib chiqmasdan oldin qayta ishlanishini ko'rsatadi.
3-misol: `requestAnimationFrame` va `setTimeout` taqqoslanishi
Brauzer muhitida requestAnimationFrame yana bir qiziqarli rejalashtirish mexanizmidir. U animatsiyalar uchun mo'ljallangan va odatda makrotasklardan keyin, lekin boshqa render yangilanishlaridan oldin qayta ishlanadi. Uning ustuvorligi odatda setTimeout(..., 0) dan yuqori, lekin mikrotasklardan pastroq.
Ko'rib chiqing:
console.log('Start');
setTimeout(() => console.log('setTimeout'), 0);
requestAnimationFrame(() => console.log('requestAnimationFrame'));
Promise.resolve().then(() => console.log('Promise'));
console.log('End');
Kutilayotgan natija:
Start
End
Promise
setTimeout
requestAnimationFrame
Sababi:
- Skript ijrosi 'Start', 'End' ni konsolga chiqaradi,
setTimeoutuchun makrotaskni va Promise uchun mikrotaskni navbatga qo'yadi. - Event Loop mikrotaskni qayta ishlaydi: 'Promise' konsolga chiqariladi.
- Keyin Event Loop makrotaskni qayta ishlaydi: 'setTimeout' konsolga chiqariladi.
- Makrotasklar va mikrotasklar bajarilgandan so'ng, brauzerning render quvuri ishga tushadi.
requestAnimationFrameqayta chaqiruvlari odatda ushbu bosqichda, keyingi kadr chizilishidan oldin bajariladi. Shuning uchun 'requestAnimationFrame' konsolga chiqariladi.
Bu, animatsiyalarni silliq va sezgir saqlashni ta'minlaydigan har qanday global dasturchi uchun interaktiv UI'larni yaratishda juda muhimdir.
Global dasturchilar uchun amaliy tushunchalar
Event Loop mexanikasini tushunish akademik mashg'ulot emas; bu butun dunyo bo'ylab mustahkam ilovalar yaratish uchun sezilarli afzalliklarga ega:
- Bashorat qilinadigan samaradorlik: Ijro tartibini bilish orqali, siz kodingiz qanday ishlashini, ayniqsa foydalanuvchi o'zaro ta'sirlari, tarmoq so'rovlari yoki taymerlar bilan ishlaganda, oldindan aytib bera olasiz. Bu foydalanuvchining geografik joylashuvi yoki internet tezligidan qat'i nazar, yanada bashorat qilinadigan dastur samaradorligiga olib keladi.
- Kutilmagan xatti-harakatlardan qochish: Mikrotask va makrotask ustuvorligini noto'g'ri tushunish kutilmagan kechikishlarga yoki noto'g'ri tartibdagi ijroga olib kelishi mumkin, bu esa ayniqsa taqsimlangan tizimlar yoki murakkab asinxron ish oqimlariga ega ilovalarni tuzatishda g'azablantirishi mumkin.
- Foydalanuvchi tajribasini optimallashtirish: Global auditoriyaga xizmat ko'rsatadigan ilovalar uchun sezgirlik asosiy hisoblanadi. Vaqtga sezgir yangilanishlar uchun strategik ravishda Promise'lar va
async/await(mikrotasklarga tayanadigan) dan foydalanib, fon operatsiyalari sodir bo'layotganda ham UI silliq va interaktiv bo'lib qolishini ta'minlashingiz mumkin. Masalan, kamroq muhim fon vazifalarini qayta ishlashdan oldin, foydalanuvchi harakatidan so'ng darhol UI'ning muhim qismini yangilash. - Resurslarni samarali boshqarish (Node.js): Node.js muhitida
process.nextTick()ni va uning boshqa mikrotasklar va makrotasklar bilan aloqasini tushunish asinxron I/O operatsiyalarini samarali boshqarish uchun juda muhim bo'lib, muhim qayta chaqiruvlarning tezda qayta ishlanishini ta'minlaydi. - Murakkab asinxronlikni tuzatish: Tuzatish paytida, brauzerning ishlab chiquvchi vositalaridan (masalan, Chrome DevTools'ning Performance yorlig'i) yoki Node.js tuzatish vositalaridan foydalanish Event Loop faoliyatini vizual tarzda aks ettirishi mumkin, bu sizga qiyinchiliklarni aniqlashga va ijro oqimini tushunishga yordam beradi.
Asinxron kod uchun eng yaxshi amaliyotlar
- Darhol davom ettirish uchun Promise'lar va
async/awaitni afzal ko'ring: Agar asinxron operatsiya natijasi darhol boshqa operatsiyani yoki yangilanishni ishga tushirishi kerak bo'lsa, ularning mikrotask rejalashtirilishi tufaylisetTimeout(..., 0)ga nisbatan tezroq ijro etilishini ta'minlaydigan Promise'lar yokiasync/awaitodatda afzal ko'riladi. - Event Loop'ga yo'l berish uchun
setTimeout(..., 0)dan foydalaning: Ba'zan siz vazifani keyingi makrotask tsikliga qoldirishni xohlashingiz mumkin. Masalan, brauzerga render yangilanishlarini amalga oshirishga ruxsat berish yoki uzoq davom etadigan sinxron operatsiyalarni bo'lish uchun. - Ichma-ich asinxronlikdan xabardor bo'ling: Misollarda ko'rinib turganidek, chuqur ichma-ich asinxron chaqiruvlar kodni tushunishni qiyinlashtirishi mumkin. Iloji boricha asinxron mantiqni tekislashni yoki murakkab asinxron oqimlarni boshqarishga yordam beradigan kutubxonalardan foydalanishni ko'rib chiqing.
- Muhitdagi farqlarni tushuning: Asosiy Event Loop tamoyillari o'xshash bo'lsa-da, maxsus xatti-harakatlar (masalan, Node.js'dagi
process.nextTick()) farq qilishi mumkin. Har doim kodingiz ishlayotgan muhitdan xabardor bo'ling. - Turli sharoitlarda sinovdan o'tkazing: Global auditoriya uchun ilovangizning sezgirligini turli tarmoq sharoitlari va qurilma imkoniyatlari ostida sinab ko'ring, bu esa izchil tajribani ta'minlaydi.
Xulosa
JavaScript Event Loop, o'zining mikrotasklar va makrotasklar uchun alohida navbatlari bilan, JavaScript'ning asinxron tabiatini ta'minlovchi jim dvigateldir. Dunyo bo'ylab dasturchilar uchun uning ustuvorlik tizimini chuqur tushunish shunchaki akademik qiziqish masalasi emas, balki yuqori sifatli, sezgir va samarali ilovalarni yaratish uchun amaliy zaruratdir. Call Stack, Mikrotasklar navbati va Makrotasklar navbati o'rtasidagi o'zaro ta'sirni o'zlashtirib, siz yanada bashorat qilinadigan kod yozishingiz, foydalanuvchi tajribasini optimallashtirishingiz va har qanday ishlab chiqish muhitida murakkab asinxron muammolarni ishonch bilan hal qilishingiz mumkin.
Tajriba qilishda, o'rganishda davom eting va kodlashdan zavqlaning!