Akış işlemede devrim yaratmak için JavaScript Async Iterator Yardımcılarını keşfedin. map, filter, take, drop ve daha fazlasıyla asenkron veri akışlarını verimli bir şekilde yönetmeyi öğrenin.
JavaScript Async Iterator Yardımcıları: Modern Uygulamalar için Güçlü Akış İşleme
Modern JavaScript geliştirmede, asenkron veri akışlarıyla uğraşmak yaygın bir gerekliliktir. İster bir API'den veri çekiyor, ister büyük dosyaları işliyor, isterse de gerçek zamanlı olayları yönetiyor olun, asenkron verileri verimli bir şekilde yönetmek çok önemlidir. JavaScript'in Async Iterator Yardımcıları, bu akışları işlemek için güçlü ve zarif bir yol sunarak, veri manipülasyonuna işlevsel ve birleştirilebilir bir yaklaşım getirir.
Async Iterator ve Async Iterable Nedir?
Async Iterator Yardımcılarına geçmeden önce, temel kavramları anlayalım: Async Iterator'lar ve Async Iterable'lar.
Bir Async Iterable, değerleri üzerinde asenkron olarak yinelenecek bir yol tanımlayan bir nesnedir. Bunu, bir Async Iterator döndüren @@asyncIterator
metodunu uygulayarak yapar.
Bir Async Iterator, bir next()
metodu sağlayan bir nesnedir. Bu metod, iki özelliğe sahip bir nesneye çözümlenen (resolve) bir promise döndürür:
value
: Dizideki bir sonraki değer.done
: Dizinin tamamen tüketilip tüketilmediğini belirten bir boolean.
İşte basit bir örnek:
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 500)); // Asenkron bir işlemi simüle et
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
for await (const value of asyncIterable) {
console.log(value); // Çıktı: 1, 2, 3, 4, 5 (her biri arasında 500ms gecikme ile)
}
})();
Bu örnekte, generateSequence
, asenkron olarak bir sayı dizisi üreten bir asenkron generator fonksiyonudur. for await...of
döngüsü, asenkron iterable'dan değerleri tüketmek için kullanılır.
Async Iterator Yardımcılarına Giriş
Async Iterator Yardımcıları, Async Iterator'ların işlevselliğini genişleterek, asenkron veri akışlarını dönüştürmek, filtrelemek ve işlemek için bir dizi metod sağlar. Veri işleme boru hatlarını (pipeline) daha kolay oluşturmayı sağlayan işlevsel ve birleştirilebilir bir programlama stili sunarlar.
Temel Async Iterator Yardımcıları şunlardır:
map()
: Akışın her bir elemanını dönüştürür.filter()
: Bir koşula göre akıştan elemanları seçer.take()
: Akışın ilk N elemanını döndürür.drop()
: Akışın ilk N elemanını atlar.toArray()
: Akışın tüm elemanlarını bir diziye toplar.forEach()
: Sağlanan bir fonksiyonu her akış elemanı için bir kez yürütür.some()
: En az bir elemanın sağlanan koşulu karşılayıp karşılamadığını kontrol eder.every()
: Tüm elemanların sağlanan koşulu karşılayıp karşılamadığını kontrol eder.find()
: Sağlanan koşulu karşılayan ilk elemanı döndürür.reduce()
: Bir akümülatör ve her eleman üzerinde bir fonksiyon uygulayarak tek bir değere indirger.
Şimdi her bir yardımcıyı örneklerle inceleyelim.
map()
map()
yardımcısı, sağlanan bir fonksiyonu kullanarak asenkron iterable'ın her bir elemanını dönüştürür. Dönüştürülmüş değerlerle yeni bir asenkron iterable döndürür.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
const doubledIterable = asyncIterable.map(x => x * 2);
(async () => {
for await (const value of doubledIterable) {
console.log(value); // Çıktı: 2, 4, 6, 8, 10 (100ms gecikme ile)
}
})();
Bu örnekte, map(x => x * 2)
dizideki her sayıyı ikiyle çarpar.
filter()
filter()
yardımcısı, sağlanan bir koşula (predicate fonksiyonu) göre asenkron iterable'dan elemanları seçer. Yalnızca koşulu sağlayan elemanları içeren yeni bir asenkron iterable döndürür.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(10);
const evenNumbersIterable = asyncIterable.filter(x => x % 2 === 0);
(async () => {
for await (const value of evenNumbersIterable) {
console.log(value); // Çıktı: 2, 4, 6, 8, 10 (100ms gecikme ile)
}
})();
Bu örnekte, filter(x => x % 2 === 0)
diziden yalnızca çift sayıları seçer.
take()
take()
yardımcısı, asenkron iterable'dan ilk N elemanı döndürür. Yalnızca belirtilen sayıda elemanı içeren yeni bir asenkron iterable döndürür.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
const firstThreeIterable = asyncIterable.take(3);
(async () => {
for await (const value of firstThreeIterable) {
console.log(value); // Çıktı: 1, 2, 3 (100ms gecikme ile)
}
})();
Bu örnekte, take(3)
diziden ilk üç sayıyı seçer.
drop()
drop()
yardımcısı, asenkron iterable'dan ilk N elemanı atlar ve geri kalanını döndürür. Kalan elemanları içeren yeni bir asenkron iterable döndürür.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
const afterFirstTwoIterable = asyncIterable.drop(2);
(async () => {
for await (const value of afterFirstTwoIterable) {
console.log(value); // Çıktı: 3, 4, 5 (100ms gecikme ile)
}
})();
Bu örnekte, drop(2)
diziden ilk iki sayıyı atlar.
toArray()
toArray()
yardımcısı, tüm asenkron iterable'ı tüketir ve tüm elemanları bir diziye toplar. Tüm elemanları içeren bir diziye çözümlenen bir promise döndürür.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const numbersArray = await asyncIterable.toArray();
console.log(numbersArray); // Çıktı: [1, 2, 3, 4, 5]
})();
Bu örnekte, toArray()
dizideki tüm sayıları bir diziye toplar.
forEach()
forEach()
yardımcısı, asenkron iterable'daki her eleman için sağlanan bir fonksiyonu bir kez yürütür. Yeni bir asenkron iterable döndürmez, fonksiyonu yan etki (side-effect) olarak çalıştırır. Bu, loglama veya bir kullanıcı arayüzünü güncelleme gibi işlemler için faydalı olabilir.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(3);
(async () => {
await asyncIterable.forEach(value => {
console.log("Değer:", value);
});
console.log("forEach tamamlandı");
})();
// Çıktı: Değer: 1, Değer: 2, Değer: 3, forEach tamamlandı
some()
some()
yardımcısı, asenkron iterable'daki en az bir elemanın sağlanan fonksiyon tarafından uygulanan testi geçip geçmediğini test eder. Bir boolean değere (en az bir eleman koşulu karşılıyorsa true
, aksi takdirde false
) çözümlenen bir promise döndürür.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const hasEvenNumber = await asyncIterable.some(x => x % 2 === 0);
console.log("Çift sayı var mı:", hasEvenNumber); // Çıktı: Çift sayı var mı: true
})();
every()
every()
yardımcısı, asenkron iterable'daki tüm elemanların sağlanan fonksiyon tarafından uygulanan testi geçip geçmediğini test eder. Bir boolean değere (tüm elemanlar koşulu karşılıyorsa true
, aksi takdirde false
) çözümlenen bir promise döndürür.
async function* generateSequence(end) {
for (let i = 2; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(4);
(async () => {
const areAllEven = await asyncIterable.every(x => x % 2 === 0);
console.log("Hepsi çift mi:", areAllEven); // Çıktı: Hepsi çift mi: true
})();
find()
find()
yardımcısı, asenkron iterable'da sağlanan test fonksiyonunu karşılayan ilk elemanı döndürür. Hiçbir değer test fonksiyonunu karşılamazsa, undefined
döndürülür. Bulunan elemana veya undefined
'a çözümlenen bir promise döndürür.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const firstEven = await asyncIterable.find(x => x % 2 === 0);
console.log("İlk çift sayı:", firstEven); // Çıktı: İlk çift sayı: 2
})();
reduce()
reduce()
yardımcısı, asenkron iterable'ın her elemanı üzerinde kullanıcı tarafından sağlanan bir "reducer" geri arama fonksiyonunu sırayla çalıştırır ve önceki eleman üzerindeki hesaplamadan gelen dönüş değerini aktarır. Reducer'ın tüm elemanlar üzerinde çalıştırılmasının nihai sonucu tek bir değerdir. Son birikmiş değere çözümlenen bir promise döndürür.
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(5);
(async () => {
const sum = await asyncIterable.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log("Toplam:", sum); // Çıktı: Toplam: 15
})();
Pratik Örnekler ve Kullanım Alanları
Async Iterator Yardımcıları çeşitli senaryolarda değerlidir. Bazı pratik örneklere göz atalım:
1. Akış API'sinden Gelen Veriyi İşleme
Bir akış API'sinden veri alan gerçek zamanlı bir veri görselleştirme panosu oluşturduğunuzu hayal edin. API sürekli olarak güncellemeler gönderir ve en son bilgileri görüntülemek için bu güncellemeleri işlemeniz gerekir.
async function* fetchDataFromAPI(url) {
let response = await fetch(url);
if (!response.body) {
throw new Error("ReadableStream bu ortamda desteklenmiyor");
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
const chunk = decoder.decode(value);
// API'nin yeni satırlarla ayrılmış JSON nesneleri gönderdiğini varsayalım
const lines = chunk.split('\n');
for (const line of lines) {
if (line.trim() !== '') {
yield JSON.parse(line);
}
}
}
} finally {
reader.releaseLock();
}
}
const apiURL = 'https://example.com/streaming-api'; // API URL'nizle değiştirin
const dataStream = fetchDataFromAPI(apiURL);
// Veri akışını işle
(async () => {
for await (const data of dataStream.filter(item => item.type === 'metric').map(item => ({ timestamp: item.timestamp, value: item.value }))) {
console.log('İşlenmiş Veri:', data);
// Panoyu işlenmiş veriyle güncelle
}
})();
Bu örnekte, fetchDataFromAPI
bir akış API'sinden veri çeker, JSON nesnelerini ayrıştırır ve bunları bir asenkron iterable olarak yield eder. filter
yardımcısı yalnızca metrikleri seçer ve map
yardımcısı, panoyu güncellemeden önce veriyi istenen formata dönüştürür.
2. Büyük Dosyaları Okuma ve İşleme
Müşteri verileri içeren büyük bir CSV dosyasını işlemeniz gerektiğini varsayalım. Tüm dosyayı belleğe yüklemek yerine, Async Iterator Yardımcılarını kullanarak dosyayı parça parça işleyebilirsiniz.
async function* readLinesFromFile(filePath) {
const file = await fsPromises.open(filePath, 'r');
try {
let buffer = Buffer.alloc(1024);
let fileOffset = 0;
let remainder = '';
while (true) {
const { bytesRead } = await file.read(buffer, 0, buffer.length, fileOffset);
if (bytesRead === 0) {
if (remainder) {
yield remainder;
}
break;
}
fileOffset += bytesRead;
const chunk = buffer.toString('utf8', 0, bytesRead);
const lines = chunk.split('\n');
lines[0] = remainder + lines[0];
remainder = lines.pop() || '';
for (const line of lines) {
yield line;
}
}
} finally {
await file.close();
}
}
const filePath = './customer_data.csv'; // Dosya yolunuzla değiştirin
const lines = readLinesFromFile(filePath);
// Satırları işle
(async () => {
for await (const customerData of lines.drop(1).map(line => line.split(',')).filter(data => data[2] === 'USA')) {
console.log('ABD'den Müşteri:', customerData);
// ABD'den müşteri verilerini işle
}
})();
Bu örnekte, readLinesFromFile
dosyayı satır satır okur ve her satırı bir asenkron iterable olarak yield eder. drop(1)
yardımcısı başlık satırını atlar, map
yardımcısı satırı sütunlara ayırır ve filter
yardımcısı yalnızca ABD'den gelen müşterileri seçer.
3. Gerçek Zamanlı Olayları Yönetme
Async Iterator Yardımcıları, WebSockets gibi kaynaklardan gelen gerçek zamanlı olayları yönetmek için de kullanılabilir. Olaylar geldikçe yayan bir asenkron iterable oluşturabilir ve ardından bu olayları işlemek için yardımcıları kullanabilirsiniz.
async function* createWebSocketStream(url) {
const ws = new WebSocket(url);
yield new Promise((resolve, reject) => {
ws.onopen = () => {
resolve();
};
ws.onerror = (error) => {
reject(error);
};
});
try {
while (ws.readyState === WebSocket.OPEN) {
yield new Promise((resolve, reject) => {
ws.onmessage = (event) => {
resolve(JSON.parse(event.data));
};
ws.onerror = (error) => {
reject(error);
};
ws.onclose = () => {
resolve(null); // Bağlantı kapandığında null ile çözümle
}
});
}
} finally {
ws.close();
}
}
const websocketURL = 'wss://example.com/events'; // WebSocket URL'nizle değiştirin
const eventStream = createWebSocketStream(websocketURL);
// Olay akışını işle
(async () => {
for await (const event of eventStream.filter(event => event.type === 'user_login').map(event => ({ userId: event.userId, timestamp: event.timestamp }))) {
console.log('Kullanıcı Giriş Olayı:', event);
// Kullanıcı giriş olayını işle
}
})();
Bu örnekte, createWebSocketStream
bir WebSocket'ten alınan olayları yayan bir asenkron iterable oluşturur. filter
yardımcısı yalnızca kullanıcı giriş olaylarını seçer ve map
yardımcısı veriyi istenen formata dönüştürür.
Async Iterator Yardımcılarını Kullanmanın Faydaları
- Geliştirilmiş Kod Okunabilirliği ve Sürdürülebilirliği: Async Iterator Yardımcıları, işlevsel ve birleştirilebilir bir programlama stilini teşvik ederek kodunuzun okunmasını, anlaşılmasını ve sürdürülmesini kolaylaştırır. Yardımcıların zincirlenebilir yapısı, karmaşık veri işleme boru hatlarını kısa ve bildirimsel bir şekilde ifade etmenizi sağlar.
- Verimli Bellek Kullanımı: Async Iterator Yardımcıları, veri akışlarını tembel (lazy) bir şekilde işler, yani veriyi yalnızca gerektiğinde işlerler. Bu, özellikle büyük veri setleri veya sürekli veri akışlarıyla uğraşırken bellek kullanımını önemli ölçüde azaltabilir.
- Artırılmış Performans: Veriyi bir akış halinde işleyerek, Async Iterator Yardımcıları tüm veri setini bir kerede belleğe yükleme ihtiyacını ortadan kaldırarak performansı artırabilir. Bu, özellikle büyük dosyaları, gerçek zamanlı verileri veya akış API'lerini işleyen uygulamalar için faydalı olabilir.
- Basitleştirilmiş Asenkron Programlama: Async Iterator Yardımcıları, asenkron programlamanın karmaşıklıklarını soyutlayarak, asenkron veri akışlarıyla çalışmayı kolaylaştırır. Promise'leri veya callback'leri manuel olarak yönetmek zorunda kalmazsınız; yardımcılar asenkron işlemleri perde arkasında halleder.
- Birleştirilebilir ve Yeniden Kullanılabilir Kod: Async Iterator Yardımcıları birleştirilebilir olacak şekilde tasarlanmıştır, yani karmaşık veri işleme boru hatları oluşturmak için onları kolayca zincirleyebilirsiniz. Bu, kodun yeniden kullanımını teşvik eder ve kod tekrarını azaltır.
Tarayıcı ve Çalışma Zamanı Desteği
Async Iterator Yardımcıları JavaScript'te hala nispeten yeni bir özelliktir. 2024'ün sonları itibarıyla, TC39 standardizasyon sürecinin 3. Aşamasındadırlar, bu da yakın gelecekte standartlaştırılma olasılıklarının yüksek olduğu anlamına gelir. Ancak, henüz tüm tarayıcılarda ve Node.js sürümlerinde yerel olarak desteklenmemektedirler.
Tarayıcı Desteği: Chrome, Firefox, Safari ve Edge gibi modern tarayıcılar, Async Iterator Yardımcıları için yavaş yavaş destek eklemektedir. Bu özelliği hangi tarayıcıların desteklediğini görmek için Can I use... gibi web sitelerindeki en son tarayıcı uyumluluk bilgilerini kontrol edebilirsiniz.
Node.js Desteği: Node.js'nin son sürümleri (v18 ve üzeri), Async Iterator Yardımcıları için deneysel destek sağlar. Bunları kullanmak için Node.js'i --experimental-async-iterator
bayrağıyla çalıştırmanız gerekebilir.
Polyfill'ler: Async Iterator Yardımcılarını yerel olarak desteklemeyen ortamlarda kullanmanız gerekiyorsa, bir polyfill kullanabilirsiniz. Bir polyfill, eksik işlevselliği sağlayan bir kod parçasıdır. Async Iterator Yardımcıları için birkaç polyfill kütüphanesi mevcuttur; popüler bir seçenek core-js
kütüphanesidir.
Özel Async Iterator'ları Uygulama
Async Iterator Yardımcıları, mevcut asenkron iterable'ları işlemek için uygun bir yol sağlarken, bazen kendi özel asenkron iterator'larınızı oluşturmanız gerekebilir. Bu, veritabanları, API'ler veya dosya sistemleri gibi çeşitli kaynaklardan gelen verileri akış halinde işlemenize olanak tanır.
Özel bir asenkron iterator oluşturmak için, bir nesne üzerinde @@asyncIterator
metodunu uygulamanız gerekir. Bu metod, bir next()
metoduna sahip bir nesne döndürmelidir. next()
metodu, value
ve done
özelliklerine sahip bir nesneye çözümlenen bir promise döndürmelidir.
İşte sayfalandırılmış bir API'den veri çeken özel bir asenkron iterator örneği:
async function* fetchPaginatedData(baseURL) {
let page = 1;
let hasMore = true;
while (hasMore) {
const url = `${baseURL}?page=${page}`;
const response = await fetch(url);
const data = await response.json();
if (data.results.length === 0) {
hasMore = false;
break;
}
for (const item of data.results) {
yield item;
}
page++;
}
}
const apiBaseURL = 'https://api.example.com/data'; // API URL'nizle değiştirin
const paginatedData = fetchPaginatedData(apiBaseURL);
// Sayfalandırılmış veriyi işle
(async () => {
for await (const item of paginatedData) {
console.log('Öğe:', item);
// Öğeyi işle
}
})();
Bu örnekte, fetchPaginatedData
sayfalandırılmış bir API'den veri çeker ve her öğeyi alındıkça yield eder. Asenkron iterator, sayfalama mantığını yöneterek veriyi akış halinde tüketmeyi kolaylaştırır.
Potansiyel Zorluklar ve Dikkat Edilmesi Gerekenler
Async Iterator Yardımcıları çok sayıda fayda sunsa da, bazı potansiyel zorlukların ve dikkat edilmesi gerekenlerin farkında olmak önemlidir:
- Hata Yönetimi: Asenkron veri akışlarıyla çalışırken uygun hata yönetimi çok önemlidir. Veri getirme, işleme veya dönüştürme sırasında oluşabilecek potansiyel hataları yönetmeniz gerekir.
try...catch
bloklarını ve asenkron iterator yardımcılarınız içinde hata yönetimi tekniklerini kullanmak esastır. - İptal (Cancellation): Bazı senaryolarda, bir asenkron iterable'ın işlenmesini tamamen tüketilmeden önce iptal etmeniz gerekebilir. Bu, uzun süren işlemlerle veya belirli bir koşul karşılandıktan sonra işlemeyi durdurmak istediğiniz gerçek zamanlı veri akışlarıyla uğraşırken faydalı olabilir.
AbortController
kullanmak gibi iptal mekanizmalarını uygulamak, asenkron işlemleri etkili bir şekilde yönetmenize yardımcı olabilir. - Geri Basınç (Backpressure): Veriyi tüketilebileceğinden daha hızlı üreten veri akışlarıyla uğraşırken, geri basınç bir endişe haline gelir. Geri basınç, tüketicinin üreticiye veri yayma hızını yavaşlatması için sinyal verme yeteneğini ifade eder. Geri basınç mekanizmalarını uygulamak, bellek taşmasını önleyebilir ve veri akışının verimli bir şekilde işlenmesini sağlayabilir.
- Hata Ayıklama (Debugging): Asenkron kodu ayıklamak, senkron kodu ayıklamaktan daha zor olabilir. Async Iterator Yardımcıları ile çalışırken, veri akışını boru hattı boyunca izlemek ve olası sorunları belirlemek için hata ayıklama araçlarını ve tekniklerini kullanmak önemlidir.
Async Iterator Yardımcılarını Kullanmak İçin En İyi Uygulamalar
Async Iterator Yardımcılarından en iyi şekilde yararlanmak için aşağıdaki en iyi uygulamaları göz önünde bulundurun:
- Açıklayıcı Değişken Adları Kullanın: Her bir asenkron iterable ve yardımcının amacını açıkça belirten açıklayıcı değişken adları seçin. Bu, kodunuzun okunmasını ve anlaşılmasını kolaylaştıracaktır.
- Yardımcı Fonksiyonları Kısa Tutun: Async Iterator Yardımcılarına geçirilen fonksiyonları olabildiğince kısa ve odaklı tutun. Bu fonksiyonlar içinde karmaşık işlemler yapmaktan kaçının; bunun yerine, karmaşık mantık için ayrı fonksiyonlar oluşturun.
- Okunabilirlik için Yardımcıları Zincirleyin: Açık ve bildirimsel bir veri işleme boru hattı oluşturmak için Async Iterator Yardımcılarını birbirine zincirleyin. Yardımcıları aşırı derecede iç içe geçirmekten kaçının, çünkü bu kodunuzun okunmasını zorlaştırabilir.
- Hataları Zarifçe Yönetin: Veri işleme sırasında oluşabilecek potansiyel hataları yakalamak ve yönetmek için uygun hata yönetimi mekanizmalarını uygulayın. Sorunları teşhis etmeye ve çözmeye yardımcı olmak için bilgilendirici hata mesajları sağlayın.
- Kodunuzu Kapsamlı Bir Şekilde Test Edin: Kodunuzun çeşitli senaryoları doğru bir şekilde ele aldığından emin olmak için kapsamlı bir şekilde test edin. Bireysel yardımcıların davranışını doğrulamak için birim testleri ve genel veri işleme boru hattını doğrulamak için entegrasyon testleri yazın.
İleri Düzey Teknikler
Özel Yardımcıları Birleştirme
Mevcut yardımcıları birleştirerek veya sıfırdan yenilerini oluşturarak kendi özel asenkron iterator yardımcılarınızı oluşturabilirsiniz. Bu, işlevselliği özel ihtiyaçlarınıza göre uyarlamanıza ve yeniden kullanılabilir bileşenler oluşturmanıza olanak tanır.
async function* takeWhile(asyncIterable, predicate) {
for await (const value of asyncIterable) {
if (!predicate(value)) {
break;
}
yield value;
}
}
// Örnek Kullanım:
async function* generateSequence(end) {
for (let i = 1; i <= end; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
}
const asyncIterable = generateSequence(10);
const firstFive = takeWhile(asyncIterable, x => x <= 5);
(async () => {
for await (const value of firstFive) {
console.log(value);
}
})();
Birden Fazla Asenkron Iterable'ı Birleştirme
zip
veya merge
gibi teknikler kullanarak birden fazla asenkron iterable'ı tek bir asenkron iterable'da birleştirebilirsiniz. Bu, birden fazla kaynaktan gelen veriyi aynı anda işlemenize olanak tanır.
async function* zip(asyncIterable1, asyncIterable2) {
const iterator1 = asyncIterable1[Symbol.asyncIterator]();
const iterator2 = asyncIterable2[Symbol.asyncIterator]();
while (true) {
const result1 = await iterator1.next();
const result2 = await iterator2.next();
if (result1.done || result2.done) {
break;
}
yield [result1.value, result2.value];
}
}
// Örnek Kullanım:
async function* generateSequence1(end) {
for (let i = 1; i <= end; i++) {
yield i;
}
}
async function* generateSequence2(end) {
for (let i = 10; i <= end + 9; i++) {
yield i;
}
}
const iterable1 = generateSequence1(5);
const iterable2 = generateSequence2(5);
(async () => {
for await (const [value1, value2] of zip(iterable1, iterable2)) {
console.log(value1, value2);
}
})();
Sonuç
JavaScript Async Iterator Yardımcıları, asenkron veri akışlarını işlemek için güçlü ve zarif bir yol sunar. Veri manipülasyonuna işlevsel ve birleştirilebilir bir yaklaşım getirerek, karmaşık veri işleme boru hatları oluşturmayı kolaylaştırırlar. Async Iterator'lar ve Async Iterable'ların temel kavramlarını anlayarak ve çeşitli yardımcı metodlarda ustalaşarak, asenkron JavaScript kodunuzun verimliliğini ve sürdürülebilirliğini önemli ölçüde artırabilirsiniz. Tarayıcı ve çalışma zamanı desteği artmaya devam ettikçe, Async Iterator Yardımcıları modern JavaScript geliştiricileri için vazgeçilmez bir araç olmaya adaydır.