- Sinxron və asinxron kodun fərqini və
setTimeout-un işini izah etmək - Promise yaratmaq və
then,catch,finallyilə nəticəni emal etmək async/awaitvətry...catchilə oxunaqlı asinxron kod yazmaqPromise.allilə bir neçə işi paralel icra etmək
Kafedə ofisiant sifarişini mətbəxə verir, amma plov bişənə qədər mətbəxin qapısında dayanıb gözləmir — o, başqa masalara xidmət edir. Yemək hazır olanda isə onu gətirir. JavaScript də eyni cür işləyir: serverdən cavab, taymer, fayl kimi uzun çəkən işləri gözləyərkən səhifəni dondurmur, başqa işlərlə məşğul olur. Buna asinxron proqramlaşdırma deyilir.
Sinxron və asinxron
İndiyə qədər yazdığımız kod sinxron idi: hər əmr əvvəlkinin bitməsini gözləyir. setTimeout(funksiya, ms) isə funksiyanı göstərilən millisaniyədən sonra icra olunmaq üçün «sonraya saxlayır», proqram isə dərhal növbəti sətrə keçir. Nəticələrin sırasına diqqət et:
console.log('1. Order placed');
setTimeout(() => {
console.log('4. Plov is ready');
}, 1000);
setTimeout(() => {
console.log('3. Tea is ready');
}, 0);
console.log('2. Waiter serves another table');▸ Gözlənilən nəticə
1. Order placed 2. Waiter serves another table 3. Tea is ready 4. Plov is ready
JavaScript eyni anda yalnız bir iş görür. Hazır olan callback-lər növbəyə düşür, hadisə dövrü isə cari sinxron kod bitəndə onları bir-bir növbədən götürüb icra edir. Ona görə 0 ms gecikməli setTimeout da bütün sinxron koddan sonra işləyir.
Callback-lər və onların problemi
Asinxron iş bitəndə nəticəni almağın ən köhnə üsulu callback ötürməkdir: «Hazır olanda bu funksiyanı çağır». Bir neçə iş ardıcıl getməlidirsə, callback-lər bir-birinin içinə girir və kod sağa doğru «pilləkən» kimi uzanır. Proqramçılar buna callback hell deyirlər.
function cook(dish, callback) {
setTimeout(() => callback(`${dish} is ready`), 300);
}
cook('Plov', (first) => {
console.log(first);
cook('Dolma', (second) => {
console.log(second);
cook('Pakhlava', (third) => {
console.log(third);
});
});
});▸ Gözlənilən nəticə
Plov is ready Dolma is ready Pakhlava is ready
Promise
Promise (vəd) gələcəkdə hazır olacaq nəticəni təmsil edən obyektdir. Onun üç vəziyyəti var: pending (gözləmədə), fulfilled (uğurla yerinə yetirilib) və rejected (xəta ilə bitib). Promise yaradanda iki funksiya alırıq: uğur üçün resolve, xəta üçün reject. Nəticəni then ilə, xətanı catch ilə alırıq; finally isə hər halda işləyir.
function cook(dish, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!dish) {
reject(new Error('No dish ordered'));
} else {
resolve(`${dish} is ready`);
}
}, time);
});
}
cook('Plov', 300)
.then((message) => {
console.log(message);
return cook('Dolma', 200);
})
.then((message) => console.log(message))
.then(() => cook('', 100))
.catch((error) => console.log('Error:', error.message))
.finally(() => console.log('Kitchen closed'));▸ Gözlənilən nəticə
Plov is ready Dolma is ready Error: No dish ordered Kitchen closed
then növbəti addımı qaytarır, bütün xətalar isə bir catch-də tutulur.async və await
async/await Promise-lərlə işi adi, sinxron kod kimi yazmağa imkan verir. async sözü ilə elan olunan funksiya həmişə Promise qaytarır. Onun içində await Promise-in nəticəsini gözləyir, amma proqramın qalan hissəsini dondurmur. Xətaları isə tanış try...catch ilə tuturuq.
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function cook(dish, time) {
await wait(time);
if (!dish) throw new Error('No dish ordered');
return `${dish} is ready`;
}
async function dinner() {
try {
console.log(await cook('Plov', 300));
console.log(await cook('Dolma', 200));
console.log(await cook('', 100));
} catch (error) {
console.log('Error:', error.message);
} finally {
console.log('Kitchen closed');
}
}
dinner();▸ Gözlənilən nəticə
Plov is ready Dolma is ready Error: No dish ordered Kitchen closed
async function getScore() {
return 42;
}
const result = getScore();
console.log(result instanceof Promise);
result.then((score) => console.log('Score:', score));▸ Gözlənilən nəticə
true Score: 42
Paralel işlər və fetch
İşlər bir-birindən asılı deyilsə, onları növbə ilə gözləmək vaxt itkisidir. Promise.all bütün Promise-ləri eyni anda başladır və hamısı hazır olanda nəticələri eyni sırada massiv kimi qaytarır. Aşağıdakı üç iş ardıcıl 600 ms çəkərdi, paralel isə təxminən 300 ms çəkir. Bircə Promise uğursuz olsa, Promise.all da xəta ilə bitir.
const cook = (dish, ms) =>
new Promise((resolve) => setTimeout(() => resolve(`${dish} is ready`), ms));
async function breakfast() {
const results = await Promise.all([
cook('Tea', 300),
cook('Bread', 100),
cook('Jam', 200),
]);
console.log(results);
}
breakfast();▸ Gözlənilən nəticə
[ 'Tea is ready', 'Bread is ready', 'Jam is ready' ]
Real layihələrdə ən çox rast gələcəyin asinxron əməliyyat serverdən verilənləri fetch ilə yükləməkdir. fetch Promise qaytarır; cavab gələndə response.json() onu JavaScript obyektinə çevirir — bu da Promise-dir. Aşağıdakı nümunə sxemdir: ünvan şərti olaraq götürülüb.
async function loadWeather(city) {
try {
const response = await fetch(`https://api.example.com/weather?city=${city}`);
if (!response.ok) {
throw new Error(`Server answered ${response.status}`);
}
const data = await response.json();
console.log(`${city}: ${data.temperature} °C`);
} catch (error) {
console.log('Could not load the weather:', error.message);
}
}
loadWeather('Baku');| Üsul | Üstünlüyü | Çatışmazlığı |
|---|---|---|
| Callback | sadədir, hər yerdə işləyir | iç-içə girəndə oxunmur |
| Promise | zəncir, bir catch bütün xətalar üçün | uzun zəncirlər yenə çətin oxunur |
| async/await | adi kod kimi oxunur, try...catch | await-i unutmaq asandır |
countdown(from) asinxron funksiyasını yaz: o, from-dan 1-ə qədər ədədləri çap etsin, hər ədəddən sonra wait(300) ilə 300 ms gözləsin, sonda isə Go! çap etsin. Son sətirdəki await burada modulun ən üst səviyyəsində olduğu kimi işləyir.
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function countdown(from) {
// print from, from - 1, ..., 1 with a 300 ms pause after each number
// then print Go!
}
await countdown(3);▸ Gözlənilən nəticə
3 2 1 Go!
Əsas fikirlər
- Asinxron kod gözləmə zamanı proqramı dondurmur;
setTimeoutfunksiyanı sonraya saxlayır. - Hazır callback-lər yalnız bütün sinxron kod bitəndən sonra icra olunur (hadisə dövrü).
- Promise-in üç vəziyyəti var: pending, fulfilled, rejected; nəticə
then, xətacatchilə alınır. asyncfunksiya həmişə Promise qaytarır;awaitnəticəni gözləyir, xətalartry...catchilə tutulur.Promise.allasılı olmayan işləri paralel icra edir və nəticələri eyni sırada qaytarır.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
console.log('A'); setTimeout(() => console.log('B'), 0); console.log('C'); hansı sırada çap edəcək?