İçeriğe geç
academia.sh

Ders 05 / 17

Söz Kavramı

Sözün üç durumlu makinesi, sonucun tek kez belirlenmesi, geri çağrıların mikro göreve alınması ve zincirlemenin her adımda yeni bir söz üretmesi.

İçindekiler

Önceki ders bir eksikle kapandı: geri çağrı düzeninde eşzamansız işlem bir değer değildir. Saklanamaz, döndürülemez, başkasına verilemez. Eksiği kapatmak için “sonucu henüz belli olmayan işlem”i temsil eden bir nesne gerekir.

Bu nesne söz (promise) adını taşır. Bu ders sözün durum makinesini, üretim biçimini ve zincirleme kurallarını kurar; ölçüm kaynağı da bu derste geri çağrı arayüzünden söz arayüzüne geçer.

Üç Durumlu Makine

Bir söz, üç durumdan tam olarak birindedir:

Durum Anlamı
beklemede (pending) Sonuç henüz belli değil
yerine gelmiş (fulfilled) Bir değerle sonuçlandı
reddedilmiş (rejected) Bir nedenle sonuçlandı

Yerine gelmiş ve reddedilmiş durumların ortak adı sonuçlanmış (settled) durumdur. Geçişler tek yönlüdür: beklemede olan bir söz sonuçlanabilir, sonuçlanmış bir söz asla beklemeye dönmez ve durumunu değiştiremez.

Bu iki kısıt, önceki dersteki belirsizliklerden ikisini doğrudan ortadan kaldırır: sonuç iki kez bildirilemez, çünkü ikinci bildirim yok sayılır; sonuç bildirildikten sonra değiştirilemez, çünkü durum kalıcıdır.

Söz Üretmek

Söz döndüren bir işlev, işi başlatır ve sonucu temsil eden nesneyi hemen döndürür. Kurucu işleve verilen fonksiyona yürütücü (executor) denir; iki fonksiyon alır: sonucu belirleyen ve reddeden.

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ı" },
};

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

olcumGetir("B2").then(
  (olcum) => console.log("yerine geldi:", olcum.istasyon, olcum.deger),
  (hata) => console.log("reddedildi:", hata.message),
);

olcumGetir("D4").then(
  (olcum) => console.log("yerine geldi:", olcum.istasyon, olcum.deger),
  (hata) => console.log("reddedildi:", hata.message),
);

console.log("iki söz de beklemede");
iki söz de beklemede
yerine geldi: B2 19.8
reddedildi: D4: sensör arızası

Kaynak tablosuna arızalı bir istasyon eklendi; D4 her çağrıda reddeder. Kursun geri kalanında hata yollarını sınamak için bu istasyon kullanılacak.

Yürütücünün gövdesi eşzamanlı çalışır; olcumGetir çağrısı dönmeden zamanlayıcı kurulur. Dönen değer ise beklemede bir sözdür. Bu nedenle son satırdaki mesaj ilk yazılır.

Bir noktaya dikkat edilmelidir: iş, söz oluşturulduğunda başlar. Söz “başlatılacak iş”in değil, “başlamış işin sonucunun” temsilidir. Sonraki derste bu ayrımın pratik sonucu görülecek.

Sonuç Tek Kez Belirlenir

Durum makinesinin kalıcılığı dil tarafından güvence altındadır. Yürütücü içinde kaç kez karar verilirse verilsin, ilk karar geçerlidir.

const soz = new Promise((karar, red) => {
  karar("ilk karar");
  karar("ikinci karar");
  red(new Error("geç reddetme"));
});

soz.then(
  (deger) => console.log("değer:", deger),
  (hata) => console.log("hata:", hata.message),
);
değer: ilk karar

İkinci karar ve reddetme sessizce yok sayıldı. Geri çağrı düzeninde elle yazılan bitti bayrağının işini burada dilin kendisi yapar.

Geri Çağrılar Her Zaman Mikro Görevdir

Söz sonuçlanmış olsa bile then geri çağrısı hemen çalışmaz; mikro görev kuyruğuna alınır. Bu, önceki konudaki “bazen eşzamanlı, bazen eşzamansız” belirsizliğini ortadan kaldırır.

const soz = Promise.resolve("hazır değer");

soz.then((deger) => console.log("2 — ilk then:", deger));
soz.then((deger) => console.log("3 — ikinci then:", deger));
console.log("1 — eşzamanlı");
queueMicrotask(() => console.log("4 — sonra kaydedilen mikro görev"));
1 — eşzamanlı
2 — ilk then: hazır değer
3 — ikinci then: hazır değer
4 — sonra kaydedilen mikro görev

Promise.resolve ile üretilen söz daha yazıldığı anda yerine gelmişti; buna karşın geri çağrıları eşzamanlı kodun tamamından sonra çalıştı. Aynı söze birden çok then bağlanabilir ve hepsi kayıt sırasına göre, aynı mikro görev boşaltmasında çalışır.

Bu kural bir de yan sonuç doğurur: söz geri çağrıları mikro görev olduğundan, birbirini zincirleyen uzun bir söz dizisi görev kuyruğunu bekletebilir. Önceki konudaki açlık uyarısı sözler için de geçerlidir.

Zincirleme: Her Adım Yeni Bir Söz

then çağrısı, sözü değiştirmez; yeni bir söz döndürür. Yeni sözün sonucu, geri çağrının ne döndürdüğüne bağlıdır:

  • Sıradan bir değer döndürürse, yeni söz o değerle yerine gelir.
  • Bir söz döndürürse, yeni söz o sözün sonucunu bekler ve onunla sonuçlanır.
  • Hata atarsa, yeni söz o hatayla reddedilir.

Reddetme, kendisini işleyen bir geri çağrı bulana kadar zincirde aşağı akar. catch yalnızca reddetmeyi işleyen bir then yazımıdır; finally ise sonucu değiştirmeden her iki durumda da çalışır.

const KAYNAK = {
  A1: { gecikme: 30, deger: 21.4 },
  B2: { gecikme: 10, deger: 19.8 },
};

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

olcumGetir("B2")
  .then((olcum) => {
    console.log("1 — ham ölçüm:", olcum.deger);
    return olcum.deger;
  })
  .then((deger) => {
    if (deger > 25) throw new Error("değer aralık dışı");
    return Math.round(deger);
  })
  .then((yuvarlanmis) => {
    console.log("2 — yuvarlanmış:", yuvarlanmis);
    return olcumGetir("A1");
  })
  .then((olcum) => {
    console.log("3 — zincirin ikinci ölçümü:", olcum.istasyon, olcum.deger);
    throw new Error("işleme adımında hata");
  })
  .catch((hata) => {
    console.log("4 — yakalandı:", hata.message);
    return "kurtarma değeri";
  })
  .then((deger) => console.log("5 — catch sonrası zincir sürüyor:", deger))
  .finally(() => console.log("6 — finally her durumda çalışır"));
1 — ham ölçüm: 19.8
2 — yuvarlanmış: 20
3 — zincirin ikinci ölçümü: A1 21.4
4 — yakalandı: işleme adımında hata
5 — catch sonrası zincir sürüyor: kurtarma değeri
6 — finally her durumda çalışır

Üçüncü adım bir söz döndürdü ve zincir onun sonuçlanmasını bekledi; dördüncü adımdaki hata catche ulaştı; catch bir değer döndürdüğü için zincir yeniden yerine gelmiş duruma döndü ve devam etti.

Son davranış sık yanılgı üretir: catch hatayı yutar ve zinciri onarır. Hatanın devam etmesi isteniyorsa catch içinde yeniden atılmalıdır.

Sonucu bir söz olan her nesne bu zincire katılabilir. Standart, then adında bir yöntemi olan her nesneyi bu amaçla kabul eder; böyle nesnelere then taşıyan nesne (thenable) denir. Zincire giren böyle bir nesne, gerçek bir sözle aynı biçimde ele alınır.

Geri Çağrıya Göre Ne Değişti

Önceki dersin dört eksiğinden üçü doğrudan kapandı. Sonuç artık bir değerdir: saklanabilir, döndürülebilir, bir diziye konabilir. Hata yolu tek bir catch ile zincirin tamamı için yazılabilir. Sözleşme ihlalleri dil tarafından engellenir — iki kez karar verilemez, geri çağrı eşzamanlı çağrılamaz.

Kapanmayan tek eksik, işlemin hiç sonuçlanmama olasılığıdır. Beklemede kalan bir söz sonsuza kadar beklemede kalabilir; bunu çözen düzenek zaman aşımıdır ve ilerideki bir derste kurulacak.

Özet

  • Söz, sonucu henüz belli olmayan bir işlemi temsil eden değerdir; üç durumu vardır ve sonuçlandıktan sonra durumu değişmez.
  • İş, söz oluşturulduğunda başlar; söz başlamış bir işin sonucunun temsilidir.
  • Yürütücü eşzamanlı çalışır, ama then geri çağrıları her zaman mikro göreve alınır.
  • then yeni bir söz döndürür; değer döndürmek zinciri sürdürür, söz döndürmek onu bekletir, hata atmak reddetmeyi aşağı akıtır.
  • catch reddetmeyi işler ve zinciri yerine gelmiş duruma döndürür; hatanın sürmesi isteniyorsa yeniden atılmalıdır.

Sonraki Adım

Tek bir söz artık bir değer olduğuna göre, birden çok söz bir koleksiyon olarak ele alınabilir. Sonraki ders, üç istasyonu birlikte bekleyen, ilk yanıtı alan veya ilk başarılı yanıtı seçen birleştiricileri tanıtır; önceki konuda sayaç ve bayrakla elle yazılan eşgüdüm işlevi tek satıra inecek. Aynı derste, birleştiricilerin hata karşısındaki farklı davranışları da karşılaştırılacak.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat