JavaScript Generatorlari va Iteratorlari
JavaScript Generatorlari va Iteratorlari to'liq qamrovli qo'llanma, ularning xususiyatlari va amaliy foydalanish holatlari.
So'nggi yangilanish: 2024-12-14Generatorlar va Iteratorlar JavaScript'dagi kuchli xususiyatlar bo'lib, ular iteratsiya oqimini boshqarish va to'xtatilishi va davom ettirilishi mumkin bo'lgan funksiyalarni yaratish imkonini beradi. Ular ayniqsa asinxron operatsiyalarni boshqarish, cheksiz ketma-ketliklarni yaratish va katta ma'lumotlar to'plamlari bilan samarali ishlash uchun foydalidir. Ushbu qo'llanma bu tushunchalarni chuqur tushuntirish, amaliy misollar va eng yaxshi amaliyotlarni taqdim etishga qaratilgan.
Iteratorlar nima?
Iteratorlar next()
metodini belgilaydigan obyektlar bo'lib, u value
va done
xususiyatlariga ega obyektni qaytaradi. Ular to'plamning elementlariga birma-bir kirish imkonini beradi.
Generatorlar nima?
Generatorlar to'xtatilishi va davom ettirilishi mumkin bo'lgan maxsus funksiyalardir, ular bajarilishi uzluksiz bo'lmagan yagona funksiya yozish orqali iterativ algoritmni belgilash imkonini beradi.
Iterator Protokoli
Iterator protokoli obyektdan qiymatlar ketma-ketligini qanday ishlab chiqarishni belgilaydi. Obyekt quyidagi semantikaga ega next()
metodini amalga oshirsa, u iterator hisoblanadi:
const iterator = {
next: function() {
return {
value: any,
done: boolean
};
}
};
Iterable Protokoli
Iterable protokoli JavaScript obyektlariga o'zlarining iteratsiya xatti-harakatlarini belgilash yoki moslashtirish imkonini beradi. Agar obyekt @@iterator
metodini amalga oshirsa, ya'ni Symbol.iterator
kalitiga ega xususiyati bo'lsa, u iterable hisoblanadi.
const iterable = {
[Symbol.iterator]: function() {
return iterator;
}
};
Maxsus Iteratorlar Yaratish
Mana maxsus iterator yaratish misoli:
function oraliqIterator(boshlash, tugatish, qadam) {
let joriy = boshlash;
return {
next: function() {
if (joriy <= tugatish) {
const natija = { value: joriy, done: false };
joriy += qadam;
return natija;
}
return { value: undefined, done: true };
}
};
}
const iterator = oraliqIterator(0, 10, 2);
console.log(iterator.next()); // { value: 0, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 4, done: false }
console.log(iterator.next()); // { value: 6, done: false }
console.log(iterator.next()); // { value: 8, done: false }
console.log(iterator.next()); // { value: 10, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
Generator Funksiyalari
Generator funksiyalari maxsus iteratorlarga kuchli muqobil variant taqdim etadi. Ular yulduzcha (*
) yordamida aniqlanadi va bajarilishni to'xtatish va davom ettirish uchun yield
kalit so'zidan foydalanadi.
function* oraliqGenerator(boshlash, tugatish, qadam) {
for (let i = boshlash; i <= tugatish; i += qadam) {
yield i;
}
}
const generator = oraliqGenerator(0, 10, 2);
console.log(generator.next()); // { value: 0, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 4, done: false }
console.log(generator.next()); // { value: 6, done: false }
console.log(generator.next()); // { value: 8, done: false }
console.log(generator.next()); // { value: 10, done: false }
console.log(generator.next()); // { value: undefined, done: true }
Yield Kalit So'zi
yield
kalit so'zi generator funksiyalarida funksiya bajarilishini to'xtatish va davom ettirish mumkin bo'lgan nuqtalarni belgilash uchun ishlatiladi.
function* teskariSanash(boshlash) {
while (boshlash > 0) {
yield boshlash;
boshlash--;
}
}
const sanagich = teskariSanash(3);
console.log(sanagich.next().value); // 3
console.log(sanagich.next().value); // 2
console.log(sanagich.next().value); // 1
console.log(sanagich.next().done); // true
Generator Metodlari
Generatorlarning bir nechta metodlari mavjud:
next()
: Ketma-ketlikdagi keyingi qiymatni qaytaradi.return()
: Generatorni tugatadi.throw()
: Xatoni chiqaradi va generatorni tugatadi, agar xato ushlangan bo'lmasa.
function* misolGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = misolGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.return(10)); // { value: 10, done: true }
console.log(gen.next()); // { value: undefined, done: true }
Asinxron Generatorlar
Asinxron generatorlar generatorlarni Promise'lar bilan birlashtiradi, bu asinxron iteratsiyaga imkon beradi.
async function* asinxronGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}
(async () => {
for await (const qiymat of asinxronGenerator()) {
console.log(qiymat);
}
})();
// Natija:
// 1
// 2
// 3
Amaliy Foydalanish Holatlari
- Dangasa baholashni (lazy evaluation) amalga oshirish:
function* dangasaOraliq(boshlash, tugatish) {
for (let i = boshlash; i <= tugatish; i++) {
yield i;
}
}
const oraliq = dangasaOraliq(1, 1000000);
console.log(oraliq.next().value); // 1
console.log(oraliq.next().value); // 2
// Oraliqning qolgan qismi so'ralmagunga qadar hisoblanmaydi
- Asinxron operatsiyalarni boshqarish:
async function* sahifalarniOlish(url_lar) {
for (const url of url_lar) {
const javob = await fetch(url);
yield await javob.text();
}
}
(async () => {
const url_lar = ['https://api.example.com/sahifa1', 'https://api.example.com/sahifa2'];
for await (const sahifa of sahifalarniOlish(url_lar)) {
console.log(sahifa);
}
})();
- Maxsus iterable'larni amalga oshirish:
class FibonacchiKetmaKetligi {
constructor(chegara) {
this.chegara = chegara;
}
*[Symbol.iterator]() {
let a = 0, b = 1, sanoq = 0;
while (sanoq < this.chegara) {
yield a;
[a, b] = [b, a + b];
sanoq++;
}
}
}
const fib = new FibonacchiKetmaKetligi(5);
for (const son of fib) {
console.log(son);
}
// Natija:
// 0
// 1
// 1
// 2
// 3
Eng Yaxshi Amaliyotlar
- Mantiq murakkab bo'lganda iterable'lar yaratish uchun generatorlardan foydalaning.
- Generatorlar va iterable'lar bilan ishlashda
for...of
tsikllarini afzal ko'ring. - Asinxron ma'lumotlar oqimlarini boshqarish uchun asinxron generatorlardan foydalaning.
- Iterable bo'lishi kerak bo'lgan maxsus ma'lumotlar tuzilmalari uchun iterable protokolini amalga oshiring.
Umumiy Xatolar
- Generatorlar bir martalik ishlatilishini unutish:
function* birMartalikGenerator() {
yield 1;
yield 2;
}
const gen = birMartalikGenerator();
console.log([...gen]); // [1, 2]
console.log([...gen]); // [] (generator allaqachon tugagan)
- Generatorlarning dangasa baholash tabiatini noto'g'ri tushunish:
function* dangasaGenerator() {
console.log("Birinchi yield");
yield 1;
console.log("Ikkinchi yield");
yield 2;
}
const gen = dangasaGenerator();
console.log(gen.next()); // Chop etadi: "Birinchi yield", keyin { value: 1, done: false }
// "Ikkinchi yield" next() ga keyingi murojaat qilinmaguncha chop etilmaydi
Generatorlar va Async/Await
Async/await asinxron operatsiyalarni boshqarish uchun oddiyroq usul taqdim etsa-da, generatorlar asinxron oqim ustidan yanada nozikroq nazorat taklif qiladi:
// Async/await dan foydalanish
async function ma'lumotOlish(url) {
const javob = await fetch(url);
return await javob.json();
}
// Generatorlardan foydalanish
function* ma'lumotOlishGen(url) {
const javob = yield fetch(url);
const ma'lumot = yield javob.json();
return ma'lumot;
}
function generatorYurgazish(genFn) {
const gen = genFn();
function bajarish(natija) {
if (natija.done) return Promise.resolve(natija.value);
return Promise.resolve(natija.value).then(
res => bajarish(gen.next(res)),
err => bajarish(gen.throw(err))
);
}
return bajarish(gen.next());
}
generatorYurgazish(ma'lumotOlishGen.bind(null, 'https://api.example.com/ma'lumot'))
.then(ma'lumot => console.log(ma'lumot))
.catch(xato => console.error(xato));
Ishlash Samaradorligi Mulohazalari
- Generatorlar oddiy funksiyalarga nisbatan kichik ishlash qo'shimcha xarajatiga ega.
- Oddiy iteratsiyalar uchun an'anaviy tsikllar generatorlardan tezroq bo'lishi mumkin.
- Generatorlar katta yoki cheksiz ketma-ketliklar uchun xotira samaradorligida ustunlikka ega.
Brauzer va Node.js Qo'llab-quvvatlashi
Generatorlar zamonaviy brauzerlar va Node.js versiyalarida yaxshi qo'llab-quvvatlanadi. Biroq, eski muhitlar uchun Babel kabi transpilerdan foydalanishingiz kerak bo'lishi mumkin.
Tez-tez So'raladigan Savollar
- Savol: Generator funksiyasi ichida
await
dan foydalana olamanmi? Javob: Yo'q, oddiy generator funksiyasida to'g'ridan-to'g'riawait
dan foydalana olmaysiz. Biroq, sizyield
ni Promise'lar bilan ishlatishingiz yoki asinxron generator funksiyalaridan foydalanishingiz mumkin. - Savol: Generatorni massivga qanday o'girishim mumkin?
Javob: Siz yoyish operatoridan foydalanishingiz mumkin:
const massiv = [...meningGeneratorim()]
- Savol: Generatorlar iteratorlarning barcha foydalanish holatlarini almashtira oladimi? Javob: Generatorlar ko'p maxsus iteratorlar foydalanish holatlarini almashtirishi mumkin bo'lsa-da, maxsus iterator amalga oshirish ko'proq nazorat yoki yaxshiroq ishlash samaradorligini ta'minlaydigan holatlar bo'lishi mumkin.