Event Loop fazalari — timers, poll, check, close
Muammodan boshlaylik
Oldingi darsda Event Loop ning umumiy rasmini ko'rdik. Lekin amalda shunday savollar chiqadi:
setTimeout(fn, 0)vasetImmediate(fn)— qaysi birinchi ishlaydi?- Nima uchun ba'zan
setTimeoutdan oldinsetImmediateishlaydi? fs.readFilecallback qaysi fazada ishlaydi?
Bu savollarga javob berish uchun Event Loop ning fazalarini bilish kerak.
Fazalar — to'liq rasm
Node.js Event Loop 6 ta fazadan iborat. Har bir faza o'z navbatini to'liq bajaradi, keyin keyingi fazaga o'tadi.
┌─────────────────────────────────────────────────────┐
│ │
│ ┌──────────┐ │
│ │ timers │ ← setTimeout, setInterval │
│ └────┬─────┘ │
│ │ │
│ ┌────▼──────────────┐ │
│ │ pending callbacks │ ← I/O xatolari │
│ └────┬──────────────┘ │
│ │ │
│ ┌────▼──────────────┐ │
│ │ idle, prepare │ ← ichki (siz ko'rmaysiz) │
│ └────┬──────────────┘ │
│ │ │
│ ┌────▼──────────────┐ │
│ │ poll │ ← I/O callbacklar │
│ └────┬──────────────┘ │
│ │ │
│ ┌────▼──────────────┐ │
│ │ check │ ← setImmediate │
│ └────┬──────────────┘ │
│ │ │
│ ┌────▼──────────────┐ │
│ │ close callbacks │ ← socket.on('close', ...) │
│ └────┬──────────────┘ │
│ │ │
│ └──────────────────────────────────────────► │
│ (qaytadan timers) │
└─────────────────────────────────────────────────────┘
Har bir faza o'tgandan keyin — microtasklar (nextTick, Promise) bajariladi.
1. Timers fazasi
Bu fazada setTimeout va setInterval callbacklari bajariladi.
Lekin muhim nuance bor: setTimeout(fn, 100) — "100ms dan keyin bajar" degani emas. "100ms o'tgandan keyin, timers fazasiga kelganda bajar" degani.
setTimeout(() => {
console.log('100ms o\'tdi');
}, 100);
Agar timers fazasiga kelganda 100ms o'tmagan bo'lsa — bu callback keyingi aylanishda bajariladi.
setTimeout(fn, 0) haqida haqiqat
setTimeout(() => console.log('setTimeout'), 0);
0 ms deb yozsangiz ham — Node.js bu ni kamida 1ms deb qabul qiladi. Va u darhol ishlamaydi — timers fazasiga kelganda ishlaydi.
2. Pending Callbacks fazasi
Bu fazada oldingi aylanishda bajarilmay qolgan I/O callbacklari ishlaydi. Asosan TCP socket xatolari shu yerda qayta ishlanadi.
Siz bu fazani to'g'ridan-to'g'ri boshqarmaysiz — Node.js o'zi hal qiladi.
3. Poll fazasi — eng muhim faza
Bu — Event Loop ning "yurak urishi". Eng ko'p vaqt shu fazada o'tadi.
Poll fazasi ikki ish qiladi:
Birinchi: I/O callbacklarini bajaradi. fs.readFile, http.request, ma'lumotlar bazasi so'rovlari — bularning callbacklari shu yerda ishlaydi.
Ikkinchi: Agar navbat bo'sh bo'lsa — kutadi. Yangi I/O event kelishini kutadi. Lekin qancha kutadi?
Poll fazasida kutish qoidasi:
- timers navbatida callback bor? → kutmaydi, timers fazasiga o'tadi
- setImmediate bor? → kutmaydi, check fazasiga o'tadi
- Ikkalasi ham yo'q? → yangi I/O event kelguncha kutadi
Bu kutish — Node.js ning "uxlashi". CPU ni bo'sh qoldirmaydi, yangi event kelganda uyg'onadi.
Amaliy misol
const fs = require('fs');
fs.readFile('fayl.txt', (err, data) => {
// Bu callback — poll fazasida ishlaydi
console.log('Fayl o\'qildi');
});
setTimeout(() => {
console.log('setTimeout');
}, 0);
Natija:
setTimeout
Fayl o'qildi
Nima uchun setTimeout oldin? Chunki:
1. timers fazasi → setTimeout callback bor → ishlaydi
2. poll fazasi → fs.readFile callback keldi → ishlaydi
4. Check fazasi — setImmediate
Bu fazada faqat setImmediate callbacklari ishlaydi.
setImmediate — "poll fazasi tugagandan keyin, shu aylanishda bajar" degani.
const fs = require('fs');
fs.readFile('fayl.txt', () => {
setTimeout(() => console.log('setTimeout'), 0);
setImmediate(() => console.log('setImmediate'));
});
Natija — har doim:
setImmediate
setTimeout
Nima uchun? fs.readFile callback poll fazasida ishlaydi. Poll fazasidan keyin — check fazasi keladi. Shuning uchun setImmediate har doim oldin ishlaydi.
setTimeout vs setImmediate — tashqi kontekstda
// fs.readFile ICHIDA EMAS — tashqi kontekstda
setTimeout(() => console.log('setTimeout'), 0);
setImmediate(() => console.log('setImmediate'));
Bu holda natija noaniq — ba'zan setTimeout oldin, ba'zan setImmediate oldin. Nima uchun?
Sabab: Dastur boshlanayotganda qaysi fazadan boshlanishi
aniq emas. Agar timers fazasiga kelganda 1ms o'tmagan
bo'lsa → setImmediate oldin.
Agar 1ms o'tgan bo'lsa → setTimeout oldin.
Shuning uchun setImmediate vs setTimeout ni tashqi kontekstda solishtirmang — natija kafolatlanmagan.
5. Close Callbacks fazasi
Bu fazada yopilish callbacklari ishlaydi.
const net = require('net');
const server = net.createServer();
server.on('close', () => {
console.log('Server yopildi'); // close callbacks fazasida
});
server.close();
socket.destroy(), server.close() — bularning callbacklari shu fazada ishlaydi.
Microtasklar — fazalar orasida
Har bir faza tugagandan keyin — microtasklar navbati to'liq bajariladi. Keyin keyingi fazaga o'tiladi.
timers fazasi tugadi
↓
nextTick navbati bajariladi (to'liq)
↓
Promise navbati bajariladi (to'liq)
↓
pending callbacks fazasi boshlanadi
↓
...
Muhim misol
const fs = require('fs');
fs.readFile('fayl.txt', () => {
setTimeout(() => console.log('1 setTimeout'), 0);
setImmediate(() => console.log('2 setImmediate'));
Promise.resolve().then(() => console.log('3 Promise'));
process.nextTick(() => console.log('4 nextTick'));
});
Natija:
4 nextTick
3 Promise
2 setImmediate
1 setTimeout
Tartib:
fs.readFile callback (poll fazasida) ishlaydi
↓
Poll fazasi tugadi → microtasklar:
→ nextTick: "4 nextTick"
→ Promise: "3 Promise"
↓
Check fazasi:
→ setImmediate: "2 setImmediate"
↓
Microtasklar (bo'sh)
↓
Keyingi aylanish — timers fazasi:
→ setTimeout: "1 setTimeout"
Fazalarni amalda his qilish
console.log('--- Sinxron kod ---');
// Timers fazasi
setTimeout(() => console.log('[timers] setTimeout 100ms'), 100);
setTimeout(() => console.log('[timers] setTimeout 0ms'), 0);
// Check fazasi
setImmediate(() => console.log('[check] setImmediate'));
// Poll fazasi
const fs = require('fs');
fs.readFile(__filename, () => {
console.log('[poll] fs.readFile callback');
// Poll ichidan
setTimeout(() => console.log('[poll→timers] setTimeout'), 0);
setImmediate(() => console.log('[poll→check] setImmediate'));
});
// Microtasklar
process.nextTick(() => console.log('[microtask] nextTick'));
Promise.resolve().then(() => console.log('[microtask] Promise'));
console.log('--- Sinxron kod tugadi ---');
Natija:
--- Sinxron kod ---
--- Sinxron kod tugadi ---
[microtask] nextTick
[microtask] Promise
[timers] setTimeout 0ms
[check] setImmediate
[poll] fs.readFile callback
[poll→check] setImmediate
[poll→timers] setTimeout
[timers] setTimeout 100ms
Xulosa — qaysi faza nima qiladi
| Faza | Nima ishlaydi | Siz boshqarasizmi? |
|---|---|---|
| timers | setTimeout, setInterval |
Ha |
| pending callbacks | I/O xatolari | Yo'q |
| idle, prepare | Ichki | Yo'q |
| poll | fs, http, DB callbacklar |
Bilvosita |
| check | setImmediate |
Ha |
| close callbacks | socket.on('close') |
Ha |
Microtasklar (har faza orasida):
process.nextTick— eng birinchiPromise.then— ikkinchi
Qoida: setImmediate ni I/O callback ichida ishlatganda — u setTimeout(fn, 0) dan har doim oldin ishlaydi.
Keyingi dars
8-dars: setImmediate vs setTimeout vs process.nextTick — farqlari