Javascript-də "Worker"-lər
Javascript bir çox cəhətdən zəngin dildir. Onun işə yarar bir çox özəlliyi var , digər istifadəçilər tərəfindən yaradılan bir çox kitabxanası var , həm client tərəfdə , həm də server tərəfdə ( node.js , deno , bun kimi runtime - ların köməyilə ) işləyə bilir , yazılan kod bir çox platformalarda işləyir ( web , mobile , smart cihazlar , oyun proqramlaşdırılması , Aİ , data visualization və s ).
Tək thread-lı ( single threaded ) Javascript
Bütün bunlara baxmayaraq Javascript-in tək thread-lı olması bəzən problemlər yaradır. Məsələn , təsəvvür edin ki siz bir proqram hazılayırsız və onun daxilində mürəkkəb bir iş görən funksiya var. Bu funksiya işə düşən zaman bitməsi məsələn 10 saniyə çəksin. Burdakı problem odur ki bu funksiyanı işə salan zaman main thread ( loru dildə desək bütün işlərin baş verdiyi yer ) bloklanır və istifadəçi bu 10 saniyəni gözləməlidir bu isə elə də yaxşı deyil. Siz fikirləşə bilərsiz ki , biz bunu asinxron olaraq çağıra bilərik ki main thread bloklanmasın ancaq asinxron olaraq çağıranda belə yenə də proses main thread-da gedəcək deyə bloklanma olacaq. Javascriptdə asinxronluq sadəcə funksiyanın işə salınması üçündür , onun işə salındıqdan sonra icra edilməsi ( execution ) asinxron deyil və main thread-da baş verir. Məsələn:
function murekkebFunksiya(){
for ( let x = 0; x < 1000000000; x++ ){
x ** 2;
}
console.log('bitdi');
}
function test(){
console.log('a');
Promise.resolve().then(murekkebFunksiya);
console.log('b')
}
test();
// a
// b
// bitdi
Burada ilk olaraq 'a' və 'b' ekrana verilir və 'then' daxilindəki callback microtask növbəsində olduğu üçün onlardan sonra ekrana verilir. Ancaq 'b' ekrana verildikdən sonra istifadəçi "murekkebFunksiya' - nın nəticəsini 'gözləyir'. Çünki bu funksiyanın nəticəsi main thread-da hesablanır və bu müddət ərzində main thread bloklandığı üçün funksiyanın icrası bitənə qədər javascript ilə bağlı proseslər işləməyəcək.
Web worker-lər problemimizi həll edir
Bizə elə bir vasitə lazımdır ki , icra edilmə ( execution ) main thread-da yox başqa bir thread-da baş versin və nəticə bəlli olanda bizə ( daha doğrusu main thread-a ) məlumat göndərsin. Web workers məhz bunun üçündür. biz web worker istifadə etməklə hər hansı bir əməliyyatı 'arxa fonda' icra edə bilərik və əməliyyat bitəndə , onun cavabını ala bilərik Burada 'arxa fon' dedikdə , main thread-dan əlavə bir thread yaradıb , kodu orada işə salmaq nəzərdə tutulur. Kompüter arxitekturasında buna multithreading deyilir. Kod yazmağa keçməzdən əvvəl qısa formada worker növlərinə baxaq:
Web Worker ( Ağır funksiyaların və ya kodların başqa bir thread-da işlədilməsi üçün )
Dedicated Worker ( yalnız onu yaradan script üçün əlçatandır )
Shared Worker ( bir neçə script ,pəncərə , iframe və hətta worker üçün əlçatandır )
Service Worker ( Şəbəkə sorğularına müdəxilə edib , bəzi APİ-lar ilə daha yaxşı istifadəçi təcrübəsi yaratmaq üçün )
Worker-lər bizə bir çox faydalı APİ - lər ilə işləməyə imkan verir bunlara dair bəzi nümunələr:
Tam siyahi üçün bu linkə keçid edə bilərsiz: Worker daxilində mövcud olan api siyahısı
Web Worker - dən istifadə edərək , əməliyyatların 'arxa fonda' icra edilməsi
Worker istifadəsi üçün aşağıdakı addımları edirik:
Feature detection ilə hazırkı mühitdə , worker-lərin dəstəkləndiyindən əmin oluruq
Main Thread-da yeni worker yaradırıq
Main Thread-dan bu worker-ə 'postMessage' metodu ilə data göndəririk
Həmin worker scriptində , event listener ilə 'message' eventini 'dinləyərək' main thread-dan gələn dataları qəbul edirik və uyğun əməliyyatları yerinə yetiririk ( və ya onmessage event handler ilə )
Indi isə keçək kodlara:
index.js faylı
/* index.js */
// feature detection ilƏ worker dəstəyini yoxlayırıq
if ( !window.Worker ){ // => ( əgər worker dəstəklənmirsə )
// console-a məlumatı yazırıq
console.log('Hazırkı mühit worker-ləri dəstəkləmir !');
}else{ // əks halda , yəni dəstəklənirsə
// worker yaradırıq
const worker = new Worker('worker.js');
// postMessage ilə bu worker-ə data göndəririk
worker.postMessage('main thread-dan mesaj');
}
worker.js faylı
// 'message' eventini 'dinləyirik'
addEventListener('message', event => {
// main thread-dan gələn datanı götürürük
const mainThreadData = event.data;
// bu datanı console-a veririk
console.log( `mesaj : ${mainThreadData}`)
});
Bunu işə saldığınız zaman console-da mesaj : main thread-dan mesaj
yazısını görəcəksiz.
Düzdür console-a main thread-dan gələn mesajl worker işlədərk ayrı bir thread içində console-a versək də əslində burada elə də qeyri-adi birşey etmədik. Ona görə də yazının əvvəlindəki mürəkkəb funksiyanı worker ilə ayrı bir thread-da icra edək:
index.js faylı
/* index.js */
// feature detection ilƏ worker dəstəyini yoxlayırıq
if ( !window.Worker ){ // => ( əgər worker dəstəklənmirsə )
// console-a məlumatı yazırıq
console.log('Hazırkı mühit worker-ləri dəstəkləmir !');
}else{ // əks halda , yəni dəstəklənirsə
// worker yaradırıq
const worker = new Worker('worker.js');
// Əvvəlki test funksiyasını yaradırıq
function test(){
// a və b -ni sinxron olaraq console-a veririk
console.log('a');
console.log('b');
// worker-dən data göndəriləndə , həmin datanı console-a
// vermək üçün main thread-da da 'message' eventini 'dinləyirik'
worker.addEventListener("message", ({ data }) => {
console.log(data);
});
// worker-ə 'start' scriptini göndəririk
worker.postMessage('start');
}
// test funksiyasını işə salırıq
test();
}
worker.js faylı
// 'message' eventini 'dinləyirik'
addEventListener('message', event => {
// main thread-dan gələn datanı götürürük
const mainThreadData = event.data;
// əgər göndərilən data 'start' string-inə bərabərdirsə ,
// mürəkkəb funksiyanı işə sal
if ( mainThreadData === 'start' ){
murekkebFunksiya();
}
});
function murekkebFunksiya(){
for ( let x = 0; x < 1000000000; x++ ){
x ** 2;
}
console.log('bitdi');
}
Bu kodları yazıb işə saldıqdan sonra əvvəlki kimi console-a a
, b
sonda isə 'bitdi'
yazısı veriləcək. Ancaq bu zaman fərq ondadır ki , istifadəçi 'bitdi' yazısını gözləyərkən Uİ ( istifadəçi interfeysi ) aktiv qalacaq və istifadəçi digər əməliyyatlar yerinə yetirə biləcək ( click etmək , yazı yazmaq və s. ). Bu ona görə mümkün olur ki , mürəkkəb funksiya main thread-da yox , yeni bir thread-da işə düşür.
Web workerlərdən istifadə edərək bir çox məsələləri həll etmək olar. Onları necə istifadə edəcəyiniz sizin seçiminizdir. Bu yazıda worker-lərin istifadəsinə dair qısa məlumat verildi ancaq əvvəldə qeyd etdiyim kimi worker-lər haqqında danışılmalı çox mövzu var ( məs: structure clone algorithm , worker ilə transferable object istifadəsi , security məsələsi və s. ). Gələcək yazılarımızda , workerlərdən daha geniş məlumat verəcəm həmçinin , onların üstünlüklərindən və dezavantajlarından daha ətraflı danışacam
Subscribe to my newsletter
Read articles from Zaur Hamidov directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Zaur Hamidov
Zaur Hamidov
Senior Full-Stack Developer ( MEVN )