---
title: 'Eşzamansız Yineleme'
source: 'https://academia.sh/tr/kurslar/eszamansiz-javascript/eszamansiz-yineleme'
course: 'Eşzamansız JavaScript ve Çalışma Zamanı'
language: tr
updated: '2026-08-17T18:09:44+00:00'
license: 'CC BY-SA 4.0'
---

# Eşzamansız Yineleme

Eşzamansız yineleyici protokolü, for await döngüsü, eşzamansız üreteçler, erken çıkışta temizlik ve çekmeli akışın geri basınç karşısındaki üstünlüğü.

Buraya kadar her ölçüm tek seferlik bir sonuçtu: iste, bekle, al. Bir istasyon ise sürekli
veri üretir. Sonucu tek bir söz değil, ucu açık bir dizi temsil eder — ve bu dizinin
elemanları zaman içinde, birer birer gelir.

Bu ders o diziyi ele alır. Sıradan yineleme protokolü burada yetersiz kalır: bir sonraki
elemanın hazır olması beklenmelidir, oysa `next` çağrısı değeri hemen döndürmek zorundadır.
Çözüm, protokolü söz döndürecek biçimde genişletmektir.

## Eşzamansız Yineleyici Protokolü

JavaScript'te Nesneler ve Fonksiyonlar kursunda tanıtılan yineleme protokolü, `next`
çağrısında `value` ve `done` alanları taşıyan bir nesne bekler. Eşzamansız protokolde
tek fark, `next` çağrısının böyle bir nesneyle **yerine gelen bir söz** döndürmesidir.

Protokolü uygulayan nesne, `Symbol.iterator` yerine `Symbol.asyncIterator` adlı yöntemi
tanımlar.

```js
const KAYNAK = {
  A1: { gecikme: 30, deger: 21.4 },
  B2: { gecikme: 10, deger: 19.8 },
  C3: { gecikme: 20, deger: 23.1 },
  D4: { gecikme: 15, hata: "sensör arızası" },
  E5: { gecikme: 5, hata: "bağlantı yok" },
};

function olcumGetir(istasyon) {
  return new Promise((karar, red) => {
    const kayit = KAYNAK[istasyon];
    setTimeout(() => {
      if (kayit.hata) red(new Error(`${istasyon}: ${kayit.hata}`));
      else karar({ istasyon, deger: kayit.deger });
    }, kayit.gecikme);
  });
}

const olcumKaynagi = {
  istasyonlar: ["A1", "B2"],
  [Symbol.asyncIterator]() {
    const istasyonlar = this.istasyonlar;
    let dizin = 0;
    return {
      async next() {
        if (dizin >= istasyonlar.length) return { value: undefined, done: true };
        const olcum = await olcumGetir(istasyonlar[dizin]);
        dizin += 1;
        return { value: olcum, done: false };
      },
    };
  },
};

for await (const olcum of olcumKaynagi) {
  console.log("protokolden gelen:", olcum.istasyon, olcum.deger);
}
```

```
protokolden gelen: A1 21.4
protokolden gelen: B2 19.8
```

`for await` döngüsü her turda `next` çağırır, dönen sözü bekler ve `done` alanı doğru
olana kadar sürdürür. Döngünün gövdesi de eşzamansız olabilir; her tur bir öncekinin
tamamlanmasını bekler.

## Eşzamansız Üreteçler

Protokolü elle yazmak, durum değişkenlerini elle taşımak demektir. Eşzamansız üreteç bu
işi devralır: `async function*` biçiminde tanımlanır, gövdesinde hem `await` hem `yield`
kullanılabilir.

```js
const KAYNAK = {
  A1: { gecikme: 30, deger: 21.4 },
  B2: { gecikme: 10, deger: 19.8 },
  C3: { gecikme: 20, deger: 23.1 },
  D4: { gecikme: 15, hata: "sensör arızası" },
  E5: { gecikme: 5, hata: "bağlantı yok" },
};

function olcumGetir(istasyon) {
  return new Promise((karar, red) => {
    const kayit = KAYNAK[istasyon];
    setTimeout(() => {
      if (kayit.hata) red(new Error(`${istasyon}: ${kayit.hata}`));
      else karar({ istasyon, deger: kayit.deger });
    }, kayit.gecikme);
  });
}

async function* olcumAkisi(istasyonlar) {
  for (const istasyon of istasyonlar) {
    console.log("üretici: istek başlatıldı —", istasyon);
    yield await olcumGetir(istasyon);
  }
}

for await (const olcum of olcumAkisi(["A1", "B2", "C3"])) {
  console.log("tüketici: işlendi —", olcum.istasyon, olcum.deger);
}
console.log("akış bitti");
```

```
üretici: istek başlatıldı — A1
tüketici: işlendi — A1 21.4
üretici: istek başlatıldı — B2
tüketici: işlendi — B2 19.8
üretici: istek başlatıldı — C3
tüketici: işlendi — C3 23.1
akış bitti
```

Çıktıdaki sıra, bu yapının en önemli özelliğini gösterir: üretici, tüketici bir öğeyi
işlemeden bir sonrakini istemiyor. Üreteç `yield` noktasında askıya alınır ve yalnız yeni
bir `next` çağrısı geldiğinde devam eder. Buna **çekmeli (pull-based)** akış denir; hızı
tüketici belirler.

## Hata ve Erken Çıkış

Akış içindeki bir reddetme, `for await` döngüsünün bulunduğu yerde atılır ve sıradan bir
`try`/`catch` ile yakalanır. Yakalanan hata döngüyü sonlandırır.

```js
const KAYNAK = {
  A1: { gecikme: 30, deger: 21.4 },
  C3: { gecikme: 20, deger: 23.1 },
  D4: { gecikme: 15, hata: "sensör arızası" },
};

function olcumGetir(istasyon) {
  return new Promise((karar, red) => {
    const kayit = KAYNAK[istasyon];
    setTimeout(() => {
      if (kayit.hata) red(new Error(`${istasyon}: ${kayit.hata}`));
      else karar({ istasyon, deger: kayit.deger });
    }, kayit.gecikme);
  });
}

async function* olcumAkisi(istasyonlar) {
  for (const istasyon of istasyonlar) {
    yield await olcumGetir(istasyon);
  }
}

try {
  for await (const olcum of olcumAkisi(["A1", "D4", "C3"])) {
    console.log("tüketici:", olcum.istasyon, olcum.deger);
  }
} catch (hata) {
  console.log("akış hatayla durdu:", hata.message);
}
```

```
tüketici: A1 21.4
akış hatayla durdu: D4: sensör arızası
```

Üçüncü istasyona hiç sıra gelmedi: üreteç, hata atılan noktada sonlandı. Akışın hataya
rağmen sürmesi isteniyorsa, hata üretecin **içinde** yakalanıp bir sonuç nesnesine
dönüştürülmelidir — önceki dersteki `allSettled` yaklaşımının akış karşılığı budur.

Döngüden `break` ile çıkmak da üreteci sonlandırır. Bu, açılan kaynakların kapatılması
için bir fırsat sağlar: üretecin `finally` bloğu her iki durumda da çalışır.

```js
const KAYNAK = {
  A1: { gecikme: 30, deger: 21.4 },
  B2: { gecikme: 10, deger: 19.8 },
  C3: { gecikme: 20, deger: 23.1 },
};

function olcumGetir(istasyon) {
  return new Promise((karar) => {
    const kayit = KAYNAK[istasyon];
    setTimeout(() => karar({ istasyon, deger: kayit.deger }), kayit.gecikme);
  });
}

async function* olcumAkisi(istasyonlar) {
  try {
    for (const istasyon of istasyonlar) {
      yield await olcumGetir(istasyon);
    }
  } finally {
    console.log("üretici: temizlik çalıştı");
  }
}

for await (const olcum of olcumAkisi(["A1", "B2", "C3"])) {
  console.log("tüketici:", olcum.istasyon);
  if (olcum.istasyon === "B2") break;
}
console.log("döngüden çıkıldı");
```

```
tüketici: A1
tüketici: B2
üretici: temizlik çalıştı
döngüden çıkıldı
```

Temizlik, döngüden çıkılmadan önce çalıştı. Sürekli bir kaynağı — açık bir bağlantıyı,
kurulmuş bir zamanlayıcıyı — okuyan üreteçlerde bu blok zorunludur; aksi halde tüketici
vazgeçse bile kaynak açık kalır.

## Söz Dizisi Üzerinde `for await`

`for await`, eşzamansız yineleyici olmayan sıradan bir dizi üzerinde de çalışır: her
elemanı `await` ile bekler. Bu, bir söz dizisini sırayla tüketmenin kısa yoludur.

```js
const KAYNAK = {
  A1: { gecikme: 30, deger: 21.4 },
  B2: { gecikme: 10, deger: 19.8 },
  C3: { gecikme: 20, deger: 23.1 },
};

function olcumGetir(istasyon) {
  return new Promise((karar) => {
    const kayit = KAYNAK[istasyon];
    setTimeout(() => karar({ istasyon, deger: kayit.deger }), kayit.gecikme);
  });
}

const sozler = ["A1", "B2", "C3"].map((istasyon) => olcumGetir(istasyon));
for await (const olcum of sozler) {
  console.log("sırayla tüketildi:", olcum.istasyon, olcum.deger);
}
```

```
sırayla tüketildi: A1 21.4
sırayla tüketildi: B2 19.8
sırayla tüketildi: C3 23.1
```

Buradaki ayrım önemlidir: istekler **birlikte** başladı, sonuçlar **sırayla** tüketildi.
Sonuçlar dizideki sırayla işlenir; A1 en yavaş olduğu halde ilk sırada beklenir. Bu,
işleme sırasının önemli olduğu durumlarda istenen davranıştır.

## Geri Basınç

Veri Yapıları kursunda kuyruklar anlatılırken tanıtılan **geri basınç (backpressure)**
kavramı, eşzamansız akışların merkezindedir: üretici tüketiciden hızlıysa, aradaki fark
bir yerde birikmek zorundadır.

İtmeli (push-based) bir kaynakta üretici tüketiciyi beklemez; öğeler bir tampona yığılır.

```js
const tampon = [];
let uretilen = 0;

const kimlik = setInterval(() => {
  uretilen += 1;
  tampon.push({ sira: uretilen });
  if (uretilen === 6) clearInterval(kimlik);
}, 5);

await new Promise((karar) => setTimeout(karar, 45));
console.log("üretilen:", uretilen, "— tampondaki bekleyen:", tampon.length);
```

```
üretilen: 6 — tampondaki bekleyen: 6
```

Tüketici hiç okumadığı için altı öğenin altısı da bellekte bekliyor. Üretim ucu açık
olsaydı tampon sınırsız büyür ve bellek tükenirdi. Bu, bellek konusunda ele alınacak
sızıntı biçimlerinden biridir.

Çekmeli akışta bu sorun tanım gereği yoktur: üreteç bir sonraki değeri ancak istendiğinde
üretir, bu yüzden birikecek bir şey olmaz. İtmeli bir kaynağı çekmeli bir arayüzün
arkasına almak — yani tamponu sınırlamak ve dolduğunda üretimi durdurmak — akış
tasarımının temel kalıbıdır.

## Özet

- Eşzamansız yineleyici protokolü, `next` çağrısının sonucu bir sözle döndürmesi dışında
  sıradan yineleme protokolüyle aynıdır; nesne `Symbol.asyncIterator` tanımlar.
- `async function*` biçimindeki üreteçler, protokolün durum yönetimini devralır ve
  gövdede hem `await` hem `yield` kullanılmasına izin verir.
- `for await` her turda bir sonraki değeri bekler; akıştaki reddetme döngünün bulunduğu
  yerde atılır ve döngüyü sonlandırır.
- Erken çıkışta üretecin `finally` bloğu çalışır; sürekli kaynakların temizliği buraya
  yazılır.
- Çekmeli akışta hızı tüketici belirler ve geri basınç kendiliğinden oluşur; itmeli
  akışta tampon sınırlanmazsa bellek tükenir.

## Sonraki Adım

Bu konuda kullanılan ölçüm kaynağı hep aynı süreçte, zamanlayıcıyla taklit edildi. Sonraki
konu kaynağı süreç dışına taşır: ağ üzerinden istek ve yanıt. Orada istek ile yanıt
nesnelerinin yapısı, gövdenin akış halinde okunması ve bu dersteki eşzamansız yinelemenin
ağ gövdelerine doğrudan uygulanışı ele alınacak.
