Series: JavaScript Basics Lesson 44

Single-thread model

JavaScript nima uchun bitta thread'da ishlaydi, race condition muammosi, V8'dagi yagona Call Stack, main thread blocking, va 'single-threaded' aslida butun brauzerga emas, faqat JS Engine'ga tegishli ekani.

44-dars

Single-thread model

1. Oddiy ta'rif

JavaScript — **bitta thread (oqim)**da ishlaydi. Bu degani: bir vaqtning o'zida faqat bitta buyruq bajariladi. Ikkinchi buyruq birinchisi tugagunicha kutadi.

console.log('1');
console.log('2');
console.log('3');

Bu har doim 1, 2, 3 tartibida chiqadi — hech qachon parallel emas, hech qachon tartib buzilmaydi. Chunki bitta thread — bitta "ishchi" — bir vaqtda faqat bitta ishni qila oladi.

Solishtirish uchun: Java yoki C++ da siz bir nechta thread ochib, ularni parallel ishlata olasiz (masalan, bitta thread hisoblasin, ikkinchisi fayl o'qisin — bir vaqtda). JS'da bu yo'q (Web Worker alohida holat, keyinroq gaplashamiz).


2. Nega aynan shunday qilingan?

JavaScript dastlab brauzerda, DOM bilan ishlash uchun yaratilgan (1995, Brendan Eich, 10 kun ichida). DOM — bu umumiy, sinxron holat (state). Agar ikkita thread bir vaqtda bitta DOM elementini o'zgartirsa nima bo'ladi?

// Thread A: elementni o'chiryapti
element.remove();

// Thread B (bir vaqtda): xuddi shu elementga style qo'yyapti
element.style.color = 'red'; // element allaqachon yo'q!

Bu race condition deyiladi — natija tasodifiy, oldindan aytib bo'lmaydigan bo'lib qoladi. Ko'p thread'li tillarda buni oldini olish uchun lock, mutex, semaphore kabi murakkab mexanizmlar kerak bo'ladi — bu esa dasturchi uchun katta og'irlik va bug manbai.

JS dizaynerlari qaror qildi: soddalik xavfsizlikdan ustun — bitta thread, hech qanday race condition, hech qanday lock kerak emas. Narxi — uzoq davom etadigan operatsiyalar hammani to'xtatib qo'yadi (buni pastda ko'ramiz).


3. V8 darajasida bu qanday ko'rinadi?

V8 engine ichida Call Stack — bitta, yagona stack. Har qanday funksiya chaqirilganda, u shu stackga qo'yiladi, bajariladi, va olib tashlanadi.

Call Stack (bitta, yagona):
┌─────────────┐
│  funcC()    │ ← hozir bajarilyapti
├─────────────┤
│  funcB()    │
├─────────────┤
│  funcA()    │
├─────────────┤
│  main()     │
└─────────────┘

Ikkinchi bir "Call Stack 2" yo'q. Shuning uchun JS Engine — bitta thread'da, bitta Call Stack bilan ishlaydi. Bu — Node.js'da ham, brauzerda ham bir xil (chunki ikkalasi ham V8 ishlatadi).


4. Bitta thread'ning "og'riq nuqtasi" — Blocking

Agar Call Stack'da bitta funksiya uzoq vaqt ishlasa, undan keyingi hech narsa bajarila olmaydi — hatto UI render ham:

function heavyTask() {
  const start = Date.now();
  while (Date.now() - start < 5000) {} // 5 sekund CPU'ni band qiladi
}

console.log('Boshlandi');
heavyTask();
console.log('Tugadi'); // 5 sekunddan keyin chiqadi

Shu 5 sekund ichida:

  • Brauzer sahifa render qila olmaydi (sahifa "muzlab" qoladi)
  • Foydalanuvchi tugma bosolmaydi
  • Hech qanday boshqa JS kod ishlamaydi

Bu — "main thread blocking" deyiladi. Va aynan shu muammoni hal qilish uchun Web APIs + Event Loop kerak bo'ladi — bu keyingi mavzumiz.


5. Muhim tushuncha — "Single-threaded" nima demaydi

Ko'p odam adashadigan joy: JS "single-threaded" degani — butun brauzer bitta thread'da ishlaydi, degani emas.

Aslida:

  • JS Engine (V8) — bitta thread'da ishlaydi (Main Thread / JS Thread)
  • Lekin brauzerning o'zi ko'p thread'li: tarmoq so'rovlari (network), fayl o'qish, timer'lar, rendering — bularning ko'pi alohida thread'larda, C++ darajasida, brauzer ichida bajariladi
Brauzer (ko'p thread):
┌─────────────────────────────────────┐
│  JS Engine Thread (V8) — bitta      │ ← bizning kodimiz shu yerda
├─────────────────────────────────────┤
│  Network Thread (fetch, XHR)         │ ← alohida
├─────────────────────────────────────┤
│  Timer Thread (setTimeout)           │ ← alohida
├─────────────────────────────────────┤
│  Rendering Thread                    │ ← alohida
└─────────────────────────────────────┘

Ya'ni: JS kodining o'zi bitta joyda, ketma-ket ishlaydi, lekin uni o'rab turgan environment (brauzer yoki Node.js) ko'p ishni fon (background)da parallel bajara oladi. Aynan shu ikkisining (bitta JS thread + ko'p background thread) birga ishlashi — Event Loop orqali amalga oshadi.


Xulosa

JavaScript — bitta thread, bitta Call Stack bilan ishlaydi, shuning uchun kod har doim ketma-ket, oldindan aytib bo'ladigan tartibda bajariladi va race condition kabi ko'p thread'li tillarga xos muammolar mavjud emas — buning narxi shundaki, Call Stack'ni uzoq band qilib turadigan har qanday operatsiya butun sahifani (render, foydalanuvchi input'i, boshqa JS kod) bloklaydi. Bu cheklovni "single-threaded" JS Engine (V8) bilan chalkashtirmaslik kerak: uni o'rab turgan brauzer yoki Node.js muhiti ko'p thread'li bo'lib, network, timer va rendering kabi ishlarni fon rejimida parallel bajaradi, va aynan shu JS thread bilan background thread'lar o'rtasidagi muvofiqlashtirish Event Loop orqali amalga oshadi — bu keyingi mavzu.