.then/.catch/.finally ishlovchilari doimo asinxrondir.
Vaâda zudlik bilan hal qilingan taqdirda ham, sizning .then/.catch/.finally satrlaringizdagidan quyidagi kod birinchi boâlib bajariladi.
Buni koârsatadigan kod:
let promise = Promise.resolve();
promise.then(() => alert("va'da bajarildi"));
alert("kod tugadi"); // birinchi navbatda ushbu ogohlantirish ko'rsatiladi
Agar siz uni ishlatsangiz, avval kod tugadi, soângra va'da tugadi ni koârasiz.
Bu gâalati, chunki vaâda boshidanoq albatta amalga oshiriladi.
Nima uchun .then keyin bajariladi? Nima boâlyapti?
Mikrovazifalar
Asinxron vazifalar toâgâri boshqaruvga muhtoj. Buning uchun standart PromiseJobs ichki navbatini belgilaydi, koâpincha âmikrovazifa navbatâ deb nomlanadi (v8 atama).
Spetsifikatsiyada aytilganidek:
- Navbat birinchi boâlib amalga oshiriladi: birinchi navbatda vazifalar boâlib bajariladi.
- Vazifani bajarish faqat boshqa hech narsa ishlamay qolganda boshlanadi.
Yoki sodda qilib aytganda, vaâda tayyor boâlganda, uning .then/catch/finally ishlovchilari navbatga qoâyiladi. Ular hali bajarilmagan. JavaScript interpretatori navbatdan vazifani oladi va joriy koddan qutilganda uni bajaradi.
Shuning uchun yuqoridagi misolda âkod tugadiâ birinchi boâlib koârsatilgan.
Vaâda beruvchilar doimo ushbu ichki navbatdan oâtadilar.
Agar bir nechta .then/catch/finally zanjiri mavjud boâlsa, unda ularning har biri asinxron tarzda bajariladi. Yaâni, u avval navbatga qoâyiladi va joriy kod tugagandan va avval navbatda turgan ishlovchilar tugagandan soâng bajariladi.
Agar navbat biz uchun muhim boâlsachi? Qanday qilib kod tugadi ni va'da bajarilgandan keyin ishlashimiz mumkin?
Oson, uni .then bilan navbatga qoâying.
Promise.resolve()
.then(() => alert("va'da bajarilgandan!"))
.then(() => alert("kod tugadi"));
Endi navbat maqsadga muvofiq.
Hodisa tsikli
Brauzer ichidagi JavaScript, shuningdek Node.js hodisa tsikliga asoslangan.
âHodisa tsikliâ â bu interpretator uxlab yotgan va hodisalarni kutib turadgan, keyin ularga javob beradigan va yana uxlaydigan jarayon.
Hodisalar misollari:
mousemove, foydalanuvchi sichqonchani harakatga keltirdi.setTimeoutishlov beruvchi chaqirildi.- tashqi
<script src ="...">yuklangan, bajarishga tayyor. - tarmoq operatsiyasi, masalan.
fetchtugallandi. - â¦va h.k.
Hodisalar sodir boâladi â interpretator ularni boshqaradi â va yana koâp narsalar boâlishini kutadi (uxlash paytida va nolga yaqin CPU isteâmol qilganda).
Koârib turganingizdek, bu yerda ham navbat bor. âMakrovazifa navbatâ deb nomlangan (v8 atama).
Hodisa sodir boâlganda, interpretator band boâlganda, uni boshqarish qulay boâladi.
Masalan, interpretator fetch tarmogâini qayta ishlash bilan band boâlganida, foydalanuvchi sichqonchani siljitib, mousemove keltirib chiqarishi mumkin, va setTimeout xuddi yuqoridagi rasmda tasvirlanganidek boâlishi kerak.
Makrovazifa navbatidagi hodisalar âbirinchi kelish â birinchi xizmatâ tamoyili asosida qayta ishlanadi. Interpretator brauzeri fetch tugagandan soâng, u mousemove hodisasini, keyin setTimeout ishlov beruvchisini va boshqalarni boshqaradi.
Hozircha juda sodda, toâgârimi? Interpretator band, shuning uchun boshqa vazifalar navbatda turadi.
Endi muhim narsalar.
Mikrovazifa navbatida makrovazifa navbatiga qaraganda ustunlik yuqori.
Boshqacha qilib aytganda, interpretator avval barcha mikrovazifalarni bajaradi, soângra makrovazifalarni oladi. Vaâda bilan ishlash har doim birinchi oâringa ega.
Masalan, qarang:
setTimeout(() => alert("timeout"));
Promise.resolve().then(() => alert("promise"));
alert("code");
Navbat qanday?
codebirinchi navbatda koârsatiladi, chunki bu muntazam sinxron chaqiruv.promiseikkinchi boâlib koârsatiladi, chunki.thenmikrovazifa navbatidan oâtadi va joriy koddan keyin ishlaydi.timeoutoxirgi oârinda koârsatiladi, chunki bu makrovazifa.
Ehtimol, makrovazifada ishlash paytida yangi vaâdalar paydo boâlishi mumkin.
Yoki, aksincha, mikrovazifa makrovazifani rejalashtiradi (masalan, setTimeout).
Masalan, .then setTimeout ni rejalashtiradi:
Promise.resolve()
.then(() => {
setTimeout(() => alert("timeout"), 0);
})
.then(() => {
alert("promise");
});
Tabiiyki, avval promise paydo boâladi, chunki setTimeout makrovazifani unchalik ahamiyatga ega boâlmagan makrovazifa navbatida kutmoqda.
Mantiqiy natija sifatida makrovazifalar faqat interpretatorga âboâsh vaqtâ berganda amalga oshiriladi. Shunday qilib, agar bizda hech narsa kutmaydigan vaâda zanjiri boâlsa, unda setTimeout yoki hodisa ishlovchilari kabi narsalar hech qachon oârtaga kira olmaydi.
Ishlov berilmagan rad etish
Va'dalar bilan ishlashda xato bobidagi âishlov berilmagan rad etishâ hodisasini eslaysizmi?
Endi mikrovazifalarni tushunish bilan biz uni rasmiylashtira olamiz.
âIshlov berilmagan rad etishâ â bu mikrovazifa navbatining oxirida vaâda xatosi koârib chiqilmaganda sodir boâladi.
Masalan, ushbu kodni koârib chiqing:
let promise = Promise.reject(new Error("Promise Failed!"));
promise.catch(err => alert('caught'));
// doesn't run: error handled
window.addEventListener('unhandledrejection', event => alert(event.reason));
Biz rad etilgan promise ni yaratamiz va xatoni koârib chiqmaymiz. Shunday qilib bizda âishlov berilmagan rad etishâ hodisasi mavjud (brauzer konsolida ham yozilgan).
Agar .catch qoâshsak, bizda bunday boâlmaydi:
let promise = Promise.reject(new Error("Promise Failed!"));
// hech qanday xato yo'q, hammasi tinch
window.addEventListener("unhandledrejection", (event) => alert(event.reason));
Endi aytaylik, biz xatoga yoâl qoâyamiz, ammo etTimeout dan keyin:
let promise = Promise.reject(new Error("Promise Failed!"));
setTimeout(() => promise.catch(err => alert('caught')), 1000);
// Error: Promise Failed!
window.addEventListener('unhandledrejection', event => alert(event.reason));
Endi ishlov berilmagan rad etish yana paydo boâladi. Nima uchun? Mikrovazifada navbat tugagandan soâng, âishlov berilmagan rad etishâ paydo boâladi. Interpretator vaâdalarni tekshiradi va agar ulardan biri ârad etilganâ holatda boâlsa, unda hodisa sodir boâladi.
Masalan, setTimeout tomonidan qoâshilgan .catch ham ishga tushadi, albatta, lekin unhandledrejection allaqachon sodir boâlgandan soâng.
Xulosa
-
Vaâdalarni boshqarish har doim ham mos kelmaydi, chunki barcha vaâda qilingan harakatlar âmikrovazifa navbatiâ (v8 atama) deb nomlangan ichki âvaâda ishiâ navbatidan oâtadi.
Shunday qilib,
.then/catch/finallyjoriy kod tugagandan soâng chaqiriladi.Agar kodning bir qismi
.then/catch/finallydan keyin bajarilishini kafolatlashimiz kerak boâlsa, uni zanjirlangan.thenchaqiruviga qoâshganimiz maâqul. -
Shuningdek, turli xil hodisalarni, tarmoq ish natijalarini,
"setTimeoutrejalashtirilgan chaqiruvlarni va boshqalarni saqlaydigan âmakrovazifa navbatiâ mavjud. Ular âmakrovazifalarâ (v8 atama) deb ham ataladi.Interpretator ularni tashqi koârinish tartibida boshqarish uchun makrovazifalrdan foydalanadi.
Makrovazifalar kod tugagandan soâng ishlaydi va mikrovazifalar navbati boâsh boâlgandan keyin.
Boshqacha qilib aytganda, ularning ustunligi pastroq.
Shunday qilib, navbat quyidagicha: odatdagi kod, keyin vaâda bilan ishlash, soângra hamma narsa, masalan hodisalar va boshqalar.
Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepenâ¦)