Microtask va Macrotask — qaysi birinchi ishlaydi
Muammodan boshlaylik
console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');
Natija nima? 1, 2, 3, 4? 1, 4, 2, 3? 1, 4, 3, 2?
Ko'pchilik noto'g'ri javob beradi. To'g'ri javob — 1, 4, 3, 2. Nima uchun setTimeout dan oldin Promise ishladi? Chunki ikkalasi turli navbatda turadi — biri macrotask, ikkinchisi microtask.
Macrotask nima?
Macrotask — "katta vazifa". Event Loop har bir aylanishida navbatdan bitta macrotask oladi va bajaradi.
Macrotask bo'ladigan narsalar:
setTimeout(() => {}, 0); // macrotask
setInterval(() => {}, 100); // macrotask (har 100ms)
setImmediate(() => {}); // macrotask (Node.js da)
fs.readFile('...', () => {}); // callback — macrotask
http.get('...', () => {}); // callback — macrotask
Macrotask navbati — oddiy navbat. Birinchi kelgan birinchi bajariladi. Har bir aylanishda faqat bitta bajariladi, keyin Event Loop keyingi ishga o'tadi.
Macrotask navbati:
┌──────────┬──────────┬──────────┐
│ callback1│ callback2│ callback3│
└──────────┴──────────┴──────────┘
↑
Bitta olinadi, bajariladi
Microtask nima?
Microtask — "kichik, lekin shoshilinch vazifa". Macrotask dan farqli — navbatdagi barcha microtasklar bitta macrotask bajarilgandan keyin darhol bajariladi.
Microtask bo'ladigan narsalar:
Promise.resolve().then(() => {}); // microtask
Promise.reject().catch(() => {}); // microtask
process.nextTick(() => {}); // microtask (Node.js, eng yuqori)
queueMicrotask(() => {}); // microtask
Microtask navbati — yuqori ustuvorlikli navbat. Har qanday macrotask dan oldin to'liq bajariladi.
Microtask navbati:
┌──────────┬──────────┬──────────┐
│ nextTick1│ Promise1 │ Promise2 │
└──────────┴──────────┴──────────┘
↑
Hammasi bajariladi — bitta ham qolmaydi
Qanday ishlaydi — to'liq rasm
Event Loop har bir aylanishida quyidagi tartibda ishlaydi:
┌─────────────────────────────────────────────────┐
│ │
│ 1. Sinxron kod bajariladi (Call Stack) │
│ │
│ 2. process.nextTick navbati — to'liq bajariladi│
│ │
│ 3. Promise microtask navbati — to'liq bajariladi│
│ │
│ 4. Bitta macrotask bajariladi │
│ (setTimeout, setImmediate, I/O callback...) │
│ │
│ 5. Yana 2-qadamga qayt │
│ │
└─────────────────────────────────────────────────┘
Muhim nuance: bitta macrotask bajarilgandan keyin — yana barcha microtasklar bajariladi. Keyin yana bitta macrotask. Va hokazo.
Qadam-baqadam misol
console.log('1'); // sinxron
setTimeout(() => console.log('2'), 0); // macrotask
Promise.resolve().then(() => console.log('3')); // microtask
console.log('4'); // sinxron
Nima bo'ladi:
Qadam 1: console.log('1') → "1" chiqadi
Qadam 2: setTimeout → macrotask navbatiga qo'yiladi
(hali bajarilmaydi)
Qadam 3: Promise.then → microtask navbatiga qo'yiladi
(hali bajarilmaydi)
Qadam 4: console.log('4') → "4" chiqadi
Qadam 5: Call Stack bo'shadi
→ microtask navbati tekshiriladi
→ Promise callback bor → "3" chiqadi
→ microtask navbati bo'shadi
Qadam 6: macrotask navbatidan bitta olinadi
→ setTimeout callback → "2" chiqadi
Natija:
1
4
3
2
Microtask ichida microtask
Microtask ichida yangi microtask qo'shilsa — u ham shu navbatda bajariladi. Macrotask ga o'tilmaydi.
Promise.resolve()
.then(() => {
console.log('1-Promise');
return Promise.resolve(); // yangi microtask
})
.then(() => {
console.log('2-Promise'); // bu ham microtask navbatida
});
setTimeout(() => console.log('setTimeout'), 0);
Natija:
1-Promise
2-Promise
setTimeout
setTimeout ikkala Promise ham tugamaguncha ishlamadi — chunki microtask navbati to'liq bo'shashi kerak.
process.nextTick — Promise dan ham oldin
Node.js da process.nextTick — alohida navbat. U Promise microtask navbatidan ham oldin ishlaydi.
Promise.resolve().then(() => console.log('Promise'));
process.nextTick(() => console.log('nextTick'));
Natija:
nextTick
Promise
Tartib:
1. process.nextTick navbati — to'liq bajariladi
2. Promise microtask navbati — to'liq bajariladi
3. Macrotask navbati — bitta bajariladi
Hammasi birgalikda
console.log('start');
setTimeout(() => console.log('setTimeout 1'), 0);
setTimeout(() => console.log('setTimeout 2'), 0);
Promise.resolve()
.then(() => console.log('Promise 1'))
.then(() => console.log('Promise 2'));
process.nextTick(() => console.log('nextTick 1'));
process.nextTick(() => console.log('nextTick 2'));
console.log('end');
Natija:
start
end
nextTick 1
nextTick 2
Promise 1
Promise 2
setTimeout 1
setTimeout 2
Tartib:
1. Sinxron: start, end
2. nextTick navbati: nextTick 1, nextTick 2
3. Promise navbati: Promise 1, Promise 2
4. Macrotask: setTimeout 1
5. Microtask tekshiriladi (bo'sh)
6. Macrotask: setTimeout 2
setTimeout 1 va setTimeout 2 alohida-alohida bajariladi — har biridan keyin microtask navbati tekshiriladi.
Xulosa
Macrotask — setTimeout, setInterval, I/O callbacklar. Navbatdan bitta olinib bajariladi.
Microtask — Promise.then, process.nextTick. Har bir macrotask dan oldin navbat to'liq bajariladi.
Tartib:
sinxron kod
↓
process.nextTick (to'liq)
↓
Promise microtask (to'liq)
↓
bitta macrotask
↓
process.nextTick (to'liq)
↓
Promise microtask (to'liq)
↓
bitta macrotask
↓
...
Shu tartibni bilsangiz — istalgan asinxron kodning natijasini oldindan ayta olasiz.
Keyingi dars
11-dars: path va os — join, resolve, dirname, platform, cpus