JavaScript tək axınlı (single-threaded) bir dildir, yəni eyni anda yalnız bir əməliyyatı icra edə bilər. Lakin bu, JavaScript-in eyni anda bir neçə işi yerinə yetirə bilməməsi anlamına gəlmir. Asinxron proqramlaşdırma məhz bu problemi həll etmək üçün mövcuddur.
Asinxronluq nədir?
Asinxron proqramlaşdırma kodun bloklanmamasına və digər əməliyyatların davam etməsinə imkan yaradır. Yəni, bir əməliyyat icra olunarkən, digər əməliyyatlar da eyni vaxtda icra olunmağa davam edə bilər.
Sinxron (synchronous) kod nümunəsi:
console.log("1");
console.log("2");
console.log("3");
Bu kodu icra etdikdə konsolda ardıcıl olaraq 1
, 2
, 3
çap olunacaq. Burada hər sətir əvvəlkinin tamamlanmasını gözləyir.
Asinxron (asynchronous) kod nümunəsi:
console.log("1");
setTimeout(() => console.log("2"), 1000);
console.log("3");
Bu zaman konsolda 1
, 3
, sonra isə bir saniyə gecikmə ilə 2
çap olunacaq. setTimeout
funksiyası ikinci əməliyyatı gözləməyə məcbur etmir və digər əməliyyatlar davam edir.
Asinxron əməliyyatların idarə olunması
JavaScript-də asinxron əməliyyatları idarə etmək üçün bir neçə üsul mövcuddur:
1. Callback funksiyalar
Callback, bir funksiyanın başqa bir funksiyaya arqument kimi ötürülməsi və müəyyən bir hadisə baş verdikdə çağırılmasıdır.
function fetchData(callback) {
setTimeout(() => {
callback("Məlumat gəldi!");
}, 2000);
}
fetchData(function (data) {
console.log(data);
});
Burada fetchData
funksiyası iki saniyə sonra callback funksiyanı çağırır və nəticəni ötürür.
Problemi: Callback-lər iç-içə istifadə edildikdə “Callback Hell” adlı mürəkkəb və çətin idarə olunan kod yaranır.
function step1(callback) {
setTimeout(() => {
console.log("Addım 1");
callback();
}, 1000);
}
function step2(callback) {
setTimeout(() => {
console.log("Addım 2");
callback();
}, 1000);
}
step1(() => {
step2(() => {
console.log("Bütün addımlar tamamlandı!");
});
});
Bu tip kodları daha səliqəli və oxunaqlı etmək üçün Promise və async/await metodları istifadə olunur.
2. Promise
Promise, asinxron əməliyyatların daha rahat idarə olunmasını təmin edir.
Promise yaratmaq:
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Məlumat uğurla alındı!");
}, 2000);
});
Promise istifadə etmək:
myPromise.then((data) => {
console.log(data);
});
Promise zəncirləmək (chaining):
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Xəta baş verdi", error));
Burada .then()
ardıcıl olaraq icra edilir, .catch()
isə xətanı tutur.
3. Async/Await
Async/Await, Promise-ləri daha oxunaqlı etmək üçün istifadə olunur. async
açar sözü funksiyanı asinxron edir, await
isə Promise-in nəticəsini gözləməyə imkan yaradır.
Async/Await nümunəsi:
async function fetchData() {
try {
let response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
let data = await response.json();
console.log(data);
} catch (error) {
console.error("Xəta baş verdi", error);
}
}
fetchData();
Burada await əməliyyatı bitənə qədər gözləyir və kod daha oxunaqlı olur.
Nəticə
Asinxron proqramlaşdırma, JavaScript-in güclü xüsusiyyətlərindən biridir və daha sürətli və effektiv tətbiqlər yaratmağa imkan verir. Callback-lər, Promise-lər və Async/Await metodları asinxron əməliyyatları idarə etməyə kömək edir.
Xülasə:
- Callback-lər – sadə və asan, amma “Callback Hell” problemini yaradır.
- Promise-lər – daha yaxşı idarə olunur, zəncirlənə bilər.
- Async/Await – kodu daha oxunaqlı edir və Promise-lər üzərində qurulur.
Call Stack və Event Loop
JavaScript mühərriki kodu icra edərkən Call Stack
adlı bir strukturdan istifadə edir. Call Stack
funksiyaların icra qaydasını idarə edir və onlar icra olunub bitdikdən sonra yaddaşdan silinir.
Event Loop isə Call Stack
və asinxron əməliyyatlar arasında əlaqə yaradan bir mexanizmdir. O, Call Stack
boşaldıqda Task Queue
və ya Microtask Queue
-da olan tapşırıqları icraya göndərir.
Makro və Mikro tapşırıqlar
JavaScript-də asinxron əməliyyatlar Makro tapşırıqlar
(Macro Tasks) və Mikro tapşırıqlar
(Micro Tasks) olmaqla iki əsas kateqoriyaya bölünür:
- Makro tapşırıqlar:
setTimeout
,setInterval
,setImmediate
(Node.js-də),I/O
əməliyyatları vəMessageChannel
daxildir. - Mikro tapşırıqlar:
Promise.then
,MutationObserver
vəqueueMicrotask
kimi metodlardan istifadə olunur.
Mikro tapşırıqlar makro tapşırıqlardan əvvəl icra olunur. Yəni, setTimeout
ilə təyin edilmiş bir tapşırıqdan əvvəl, eyni dövrədə (event loop
iterasiyasında) yaranmış bütün mikro tapşırıqlar icra ediləcək.
Bonus olaraq Lydia xanımdan bu prosesin necə işlədiyinin əyani olaraq izahını izləyə bilərsiniz.