Ders 06 / 17
Söz Birleştiricileri
Birden çok sözü tek sözde toplayan dört birleştirici; hata karşısındaki davranış farkları; işin ne zaman başladığı ile ne zaman beklendiğinin ayrımı.
İçindekiler
Önceki ders tek bir sözü bir değer haline getirdi. Değer olan şey diziye konabilir; diziye konan şey topluca ele alınabilir. Geri çağrı konusunda sayaç ve bayrakla elle yazılan “hepsini bekle” işlevi, artık dilin sağladığı bir işleçle yazılabilir.
Bu ders dört birleştiriciyi tanıtır ve aralarındaki asıl farkın hata karşısındaki davranış olduğunu gösterir. Ölçüm akışı burada üç istasyonu birlikte okuyan bir toplayıcıya dönüşür.
İş Ne Zaman Başlar
Birleştiricileri doğru okumak için önce bir yanlış anlamanın giderilmesi gerekir: birleştiriciler işi başlatmaz. İş, sözler oluşturulduğunda başlamıştır; birleştirici yalnız beklemeyi düzenler.
Aşağıdaki örneklerde ölçüm kaynağı, isteğin başladığı anı da yazdırır. Kurs boyunca
kullanılan tablo, arızalı D4 istasyonunu da içerir.
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) { console.log("istek başladı:", 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 olcumler = await Promise.all([olcumGetir("A1"), olcumGetir("B2"), olcumGetir("C3")]); console.log("sonuç:", olcumler.map((o) => `${o.istasyon}=${o.deger}`).join(" "));
istek başladı: A1 istek başladı: B2 istek başladı: C3 sonuç: A1=21.4 B2=19.8 C3=23.1
Üç istek de Promise.all çağrılmadan önce, dizi hazırlanırken başladı. Beklemeler üst
üste bindi; sonuç, en yavaş istek olan A1 tamamlandığında geldi.
Sonuç dizisi istek sırasını korur, geliş sırasını değil. Geri çağrı konusunda bunu sağlamak için sonuçları dizine göre yerleştirmek gerekiyordu; burada güvence birleştiricinin kendisindedir.
Hepsini Bekle: Promise.all
Promise.all, verilen sözlerin tümü yerine geldiğinde, sonuç dizisiyle yerine gelir.
Herhangi biri reddedilirse, ilk reddetmeyle birlikte hemen reddedilir.
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) { console.log("istek başladı:", 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); }); } try { await Promise.all([olcumGetir("A1"), olcumGetir("D4"), olcumGetir("C3")]); } catch (hata) { console.log("all reddedildi:", hata.message); }
istek başladı: A1 istek başladı: D4 istek başladı: C3 all reddedildi: D4: sensör arızası
İki nokta önemlidir. Birincisi, sonuç on beşinci milisaniyede belli oldu; A1 ve C3 beklenmedi. İkincisi ve daha önemlisi: beklenmemek, iptal edilmek değildir. A1 ve C3 istekleri sürmeye devam eder, sonuçları da üretilir; yalnız kimse onlara bakmaz. İptal ayrı bir düzenek gerektirir ve ilerideki bir derste kurulacak.
Bu davranış, “hepsi olmazsa hiçbiri” anlamı taşıyan işler için doğrudur: üç ölçümün ortalaması, biri eksikken hesaplanamaz.
Hepsinin Sonucunu Topla: Promise.allSettled
Kısmi sonuç kabul edilebilir olduğunda all yanlış araçtır. Promise.allSettled hiçbir
zaman reddedilmez; her söz için durumu ve sonucunu taşıyan bir kayıt döndürür.
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) { console.log("istek başladı:", 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 sonuclar = await Promise.allSettled([olcumGetir("A1"), olcumGetir("D4"), olcumGetir("C3")]); for (const s of sonuclar) { if (s.status === "fulfilled") console.log("yerine geldi:", s.value.istasyon, s.value.deger); else console.log("reddedildi:", s.reason.message); }
istek başladı: A1 istek başladı: D4 istek başladı: C3 yerine geldi: A1 21.4 reddedildi: D4: sensör arızası yerine geldi: C3 23.1
Arızalı istasyon akışı durdurmadı; iki geçerli ölçüm elde edildi ve hata da kaydedildi. Ölçüm ağı gibi kısmi verinin işe yaradığı alanlarda varsayılan seçim budur.
Kayıtların alan adları sabittir: yerine gelmiş kayıtta status ve value, reddedilmiş
kayıtta status ve reason bulunur.
İlk Sonuçlanan: Promise.race
Promise.race, hangi söz önce sonuçlanırsa onun sonucunu alır — yerine gelme ile reddetme
arasında ayrım yapmaz.
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) { console.log("istek başladı:", 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 ilk = await Promise.race([olcumGetir("A1"), olcumGetir("B2"), olcumGetir("C3")]); console.log("race sonucu:", ilk.istasyon, ilk.deger); try { await Promise.race([olcumGetir("A1"), olcumGetir("D4")]); } catch (hata) { console.log("race reddedildi:", hata.message); }
istek başladı: A1 istek başladı: B2 istek başladı: C3 race sonucu: B2 19.8 istek başladı: A1 istek başladı: D4 race reddedildi: D4: sensör arızası
İkinci yarışta en hızlı sonuçlanan söz arızalı istasyonunkiydi; race onu da sonuç
saydı. Bu nedenle race, “en hızlı sağlıklı yanıtı al” anlamına gelmez.
Bir uyarı gerekir: yarışı kaybeden sözler yaşamaya devam eder. Hiç sonuçlanmayan bir söz
race içine konursa, o söz ve kapattığı bütün değerler program boyunca bellekte kalır.
Bu, bellek konusunda ele alınacak sızıntı türlerinden biridir.
İlk Başarılı: Promise.any
Promise.any, reddetmeleri yok sayar ve ilk yerine gelen sonucu döndürür. Hepsi
reddedilirse, tüm nedenleri içeren bir toplu hatayla reddedilir.
const KAYNAK = { A1: { gecikme: 30, deger: 21.4 }, D4: { gecikme: 15, hata: "sensör arızası" }, }; function olcumGetir(istasyon) { console.log("istek başladı:", 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 ilkBasarili = await Promise.any([olcumGetir("A1"), olcumGetir("D4")]); console.log("any sonucu:", ilkBasarili.istasyon, ilkBasarili.deger); try { await Promise.any([olcumGetir("D4")]); } catch (hata) { console.log("any reddedildi:", hata.constructor.name); console.log("içindeki hatalar:", hata.errors.map((h) => h.message).join(", ")); }
istek başladı: A1 istek başladı: D4 any sonucu: A1 21.4 istek başladı: D4 any reddedildi: AggregateError içindeki hatalar: D4: sensör arızası
Arızalı istasyon on beşinci milisaniyede reddetti; any bunu yok sayıp otuzuncu
milisaniyedeki geçerli yanıtı bekledi. Toplu hata nesnesi, tek tek nedenleri errors
dizisinde taşır — böylece hiçbir hata bilgisi kaybolmaz.
Bu birleştirici, aynı veriyi birden çok kaynaktan isteyip ilk çalışanı kullanan yedeklilik kalıbının doğrudan karşılığıdır.
Seçim Ölçütü
| Birleştirici | Yerine gelir | Reddedilir | Uygun olduğu durum |
|---|---|---|---|
all |
Hepsi yerine gelirse | İlk reddetmede | Bütün parçalar zorunlu |
allSettled |
Her zaman | Hiçbir zaman | Kısmi sonuç kabul edilebilir |
race |
İlk sonuçlanan yerine gelmişse | İlk sonuçlanan reddedilmişse | Zaman sınırı koymak |
any |
İlk yerine gelende | Hepsi reddedilirse | Yedekli kaynaklar |
Dördü de aynı girdi biçimini alır ve tek bir söz döndürür; bu nedenle iç içe
kullanılabilirler. Bir istasyon kümesinin any ile seçilen sonucu, başka bir kümenin
sonucuyla all içinde birleştirilebilir.
Özet
- Birleştiriciler işi başlatmaz; sözler oluşturulduğunda iş başlamıştır, birleştirici yalnız beklemeyi düzenler.
allsonuç dizisini istek sırasında verir ve ilk reddetmede hemen reddedilir; beklenmeyen istekler iptal edilmez, sürmeye devam eder.allSettledhiç reddedilmez; her söz için durum ve sonuç kaydı döndürür.raceilk sonuçlanana bakar, başarı ile başarısızlığı ayırt etmez;anyilk yerine geleni seçer ve hepsi reddedilirse nedenleri toplu bir hatada taşır.- Yarışı kaybeden ve sonuçlanmayan sözler bellekte kalmaya devam eder.
Sonraki Adım
Birleştiriciler beklemenin yapısını kurdu, ama kodun okunuşunu değiştirmedi: sonuçlar
hâlâ geri çağrıların içinde işleniyor. Sonraki ders, aynı zincirleri sıralı bir yazımla
ifade eden sözdizimsel katmanı tanıtır — async ve await. Aynı derste, bu yazımın
farkında olmadan sıralı beklemeye yol açtığı yaygın hata da gösterilecek ve bu derste
kurulan birleştiricilerle düzeltilecek.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.