Series: JavaScript Basics Lesson 45

Web APIs

setTimeout, fetch, addEventListener kabi funksiyalar aslida V8'ning bir qismi emasligi, ular brauzer/Node.js taqdim etadigan tashqi imkoniyatlar ekani, va Call Stack, Web APIs, Callback/Microtask Queue o'rtasidagi ishlash tartibi.

45-dars

Web APIs

Oldingi mavzuda ko'rdik: JS — bitta thread, va agar biror ish uzoq davom etsa (masalan, 5 sekund server javobini kutish), butun dastur muzlab qoladi.

Savol: setTimeout, fetch, addEventListener kabi funksiyalar JS ichida yozilgan bo'lsa, ular ham Call Stack'ni band qilib, hammani to'xtatib qo'yishi kerak edi-ku? Nega qilmaydi?

Javob: chunki bu funksiyalar aslida JavaScript emas. Ular brauzer (yoki Node.js) tomonidan taqdim etilgan — C++ da yozilgan, JS Engine'dan tashqarida ishlaydigan imkoniyatlar. Ularga umumiy nom — Web APIs (brauzerda) yoki Node APIs (Node.js'da, masalan fs, libuv).


1. setTimeout V8'ning bir qismi emas

Bu ko'p dasturchini hayron qoldiradi. Tekshirib ko'ramiz:

console.log(typeof setTimeout); // "function"

Xo'sh, funksiya bo'lsa, u qayerdan keladi? V8 spetsifikatsiyasida (ECMAScript standarti) setTimeout degan narsa umuman yo'q! Uni qidirib ko'rsangiz — ECMAScript spec'da topolmaysiz.

setTimeout, fetch, document, addEventListener, localStorage, console — bularning barchasi brauzer (Chrome, Firefox va h.k.) tomonidan JS Engine'ga qo'shib beriladi — bu BOM (Browser Object Model) va Web API deb ataladi. Node.js'da esa o'z APIlari bor: fs, http, process.

┌─────────────────────────────────────────────┐
│              Brauzer (Runtime)               │
│  ┌─────────────┐      ┌──────────────────┐  │
│  │  V8 Engine  │      │   Web APIs (C++)  │  │
│  │  (JS kodi)  │◄────►│  setTimeout       │  │
│  │  Call Stack │      │  fetch (XHR)      │  │
│  │  Heap       │      │  DOM              │  │
│  │             │      │  addEventListener │  │
│  └─────────────┘      └──────────────────┘  │
│         ▲                       │             │
│         │                       ▼             │
│         │              ┌──────────────────┐  │
│         └──────────────│  Callback Queue   │  │
│                         └──────────────────┘  │
└─────────────────────────────────────────────┘

V8 — faqat JS kodini bajaradi (Call Stack, Heap, Memory). Web APIs — bular brauzerning boshqa, alohida qismlari, ko'pincha o'z thread'larida ishlaydi.


2. Qadam-baqadam — setTimeout misolida

console.log('1');

setTimeout(() => {
  console.log('2');
}, 2000);

console.log('3');

Natija: 1, 3, (2 sekunddan keyin) 2. Ichkarida nima bo'ladi?

Qadam 1 — console.log('1') Call Stack'ga tushadi, bajariladi, chiqadi.

Qadam 2 — setTimeout(callback, 2000) chaqiriladi. Bu funksiyaning o'zi Call Stack'ga tushadi — lekin uning ishi juda oddiy va tez: u callback funksiyani va 2000ms qiymatini brauzerning Web API qismiga "topshiradi", so'ng darhol Call Stack'dan chiqib ketadi (setTimeoutning o'zi hech narsani "kutmaydi"!).

V8 Call Stack:          Web API (brauzer, alohida joyda):
setTimeout() → topshirdi → Timer boshlandi: 2000ms
                            (bu yerda hisoblash V8'dan TASHQARIDA ketyapti)

Qadam 3 — Call Stack bo'shaydi, console.log('3') navbatga kiradi, bajariladi.

Qadam 4 (fon jarayoni) — brauzer ichidagi Timer thread (V8'dan mustaqil, C++ darajasida) soatni sanaydi. Bu vaqt ichida V8 Call Stack'i bo'sh, boshqa kod bajarilishi mumkin — hech narsa bloklanmaydi.

Qadam 5 — 2000ms tugagach, Web API () => console.log('2') callback'ini Call Stack'ga to'g'ridan-to'g'ri qo'ymaydi — avval uni **Callback Queue (Task Queue)**ga joylashtiradi.

Qadam 6 — Event Loop (keyingi mavzumiz) doimiy tekshirib turadi: "Call Stack bo'sh-mi?" Agar bo'sh bo'lsa, Queue'dan navbatdagi callback'ni olib, Call Stack'ga qo'yadi. Faqat shundagina console.log('2') bajariladi.

Shuning uchun natija hech qachon 1, 2, 3 bo'lmaydi — setTimeout(fn, 0) yozsangiz ham, 2 hali ham 3dan keyin chiqadi, chunki callback avval Queue orqali o'tishi shart.


3. Web APIs turlari — hammasi bir xil ishlamaydi

Bu joy juda muhim, chunki keyingi mavzu (Microtask vs Macrotask) aynan shu farqga asoslanadi. Web APIlar natijani qaytarish uchun **ikki xil navbat (queue)**dan foydalanadi:

1. Macrotask (Task) Queue orqali qaytadiganlar:

setTimeout(fn, delay)
setInterval(fn, delay)
// DOM event'lar (click, scroll)

2. Microtask Queue orqali qaytadiganlar:

fetch(...).then(fn)   // Promise natijasi
// MutationObserver
queueMicrotask(fn)

fetch misolida ko'raylik:

console.log('1');

fetch('https://example.com')
  .then(() => console.log('2'));

console.log('3');

fetch chaqirilganda, V8 tarmoq so'rovini Network Thread'ga topshiradi (bu ham Web API, lekin Timer emas — Networking qismi). Call Stack darhol bo'shaydi. Server javob qaytarganda, .then() ichidagi funksiya — Microtask Queuega tushadi (Macrotask Queue'ga emas!). Bu farq amalda ijro tartibiga ta'sir qiladi — buni keyingi mavzuda (Microtask vs Macrotask) sonlar bilan ko'rsataman.


4. Node.js'da farq bormi?

Brauzerda "Web API" bor joyni, Node.js'da libuv (C tilida yozilgan kutubxona) egallaydi. setTimeout, fayl o'qish (fs.readFile), tarmoq so'rovlari — bularning barchasini libuv o'zining thread pooli (odatda 4 ta background thread) va OS darajasidagi async mexanizmlar orqali boshqaradi. V8'ning o'zi bunda ishtirok etmaydi — u faqat callback qaytganda ishga tushadi.

Node.js:
┌───────────┐     ┌─────────────────────┐
│ V8 Engine │◄───►│  libuv (C library)   │
│(JS kodi)  │     │  - Thread Pool       │
└───────────┘     │  - Event Loop phases │
                   │  - OS async I/O      │
                   └─────────────────────┘

Tamoyil bir xil qoladi: og'ir yoki kutish talab qiladigan ish V8'dan tashqariga chiqariladi, natija esa navbat (queue) orqali qaytarib beriladi.


Xulosa

setTimeout, fetch, DOM eventlar — bular JS Engine (V8)ning bir qismi emas, balki brauzer/Node.js taqdim etadigan tashqi imkoniyatlar. Bu funksiyalar chaqirilganda, og'ir/kutish ishi darhol boshqa joyga (thread yoki OS darajasiga) "topshiriladi", Call Stack esa darhol bo'shaydi. Ish tugagach, natija (callback) to'g'ridan-to'g'ri Call Stack'ga emas, balki **navbat (Callback/Microtask Queue)**ga qo'yiladi. Call Stack bilan Queue o'rtasidagi "ko'prik" — Event Loop, bu keyingi mavzumiz.