IS
Barcha tajribalar
jonli

Web Workers — interfeysni qotirmaydigan hisob-kitob

Bir xil og‘ir vazifa: asosiy oqimda u sahifani muzlatadi, Web Worker‘da esa fonda hisoblanadi — spinner va FPS uzilmaydi. Farqni jonli his qiling.

laboratoriya yozuvi
Nega qildim

Brauzerdagi JS bitta oqimli: og‘ir sikl hisoblanayotganda sahifa chizilmaydi ham, bosishga javob bermaydi ham. Buni so‘z bilan emas, qo‘l bilan ko‘rsatmoqchi edim — qotishni barmoq bilan sezish mumkin bo‘lsin, va yonida worker uni qanday olib tashlashini ko‘rsatay.

Nimani o'rgandim

Worker — bu “asinxronlik” emas, haqiqiy ikkinchi OS oqimi. U rostdan parallel hisoblaydi, lekin DOM‘ga kira olmaydi va faqat postMessage orqali gaplashadi (structured clone ma’lumotni nusxalaydi). Katta massivlar uchun transferable-buferlar bor — nusxasiz, nanosekundlarda uzatiladi.

Qayerda sindi

Birinchi variant worker‘ni Blob-URL‘dan yaratardi — kamroq fayl. Ammo saytning qat’iy CSP‘si (default-src self, blob: yo‘q) uni bloklab qo‘ydi. Worker‘ni statik fayl /workers/heavy-task.js sifatida berdim va CSP‘ga worker-src self qo‘shdim — bu ancha toza: inline kod o‘rniga same-origin.

Stek
Web WorkersrequestAnimationFrameTypeScript

Interfeys nega umuman qotadi

Brauzerdagi JavaScript bitta oqimda ishlaydi. O‘sha oqim kodingizni ham hisoblaydi, sahifani ham joylashtiradi, kadr ham chizadi va bosishlarga ham javob beradi. U bir necha soniya sinxron siklda band bo‘lsa — sahifa o‘lik: animatsiyalar to‘xtaydi, tugmalar bosilmaydi, matn maydonidagi kursor miltillamaydi.

Quyida requestAnimationFrame‘ga asoslangan jonli indikator (spinner, FPS va «puls»). **«Asosiy oqimda»**ni bosing — o‘sha rAF sikli band oqimda yashaydi, shuning uchun hisob vaqtida hammasi qotadi. Keyin **«Web Worker‘da»**ni bosing va farqni his qiling.

jonli demo
Demo yuklanmoqda…

Bu qanday ishlaydi

new Worker('/workers/heavy-task.js') alohida oqim ko‘taradi. Aloqa — faqat xabarlar orqali:

// asosiy oqim
worker.postMessage(40_000_000);
worker.onmessage = (e) => console.log(e.data.ms);
 
// worker.js — o‘zining global konteksti, window va DOM yo‘q
self.onmessage = (e) => {
  let acc = 0;
  for (let i = 0; i < e.data; i++) acc += Math.sqrt(i) * Math.sin(i);
  self.postMessage({ acc });
};

Demodagi og‘ir hisob (40 mln iteratsiyada √·sin) ikkala holatda ham bir xil — faqat qayerda bajarilishi o‘zgaradi. Asosiy oqimda UI qotishi ≈ vazifa vaqtiga teng; worker‘da esa har kadr uchun barqaror ~16 ms.

Worker’lar yana nima qila oladi

Bu eng ko‘rgazmali holat, lekin yagona emas:

  • Fondagi so‘rov va parsing — katta JSON‘ni renderni osib qo‘ymay tortib olish va tahlil qilish.
  • SharedWorker — bir nechta varaq uchun bitta oqim: umumiy soket, bitta saytning oynalari orasida holatni sinxronlash.
  • OffscreenCanvas + transferable — rasmlarni to‘g‘ridan-to‘g‘ri worker ichida filtrlash/dekodlash, piksellarni nusxasiz bufer sifatida qaytarish.

Har biri alohida yozuvga arziydi; bu yerda ildizni ko‘rsatish muhim edi: og‘irni chizadigan joyda hisoblama.