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
thengeri çağrıları her zaman mikro göreve alınır. thenyeni 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.catchreddetmeyi 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.