Ders 12 / 25
Hata Sınırları
Oluşturma sırasında atılan bir hatanın bileşen ağacında yalıtılması; yarım ağacın neden bırakılmadığı, en yakın sınırın yakalaması, sınır yerleşiminin ekranda kalan bileşen sayısına etkisi, çağrı yığınının dışına çıkan hataların kapsam dışı kalması ve kurtarma.
İçindekiler
Önceki ders bir değeri ağaçta aşağı doğru akıtan mekanizmayı kurdu. Ters yönde akan bir şey daha vardır ve bu derse kadar hiç ele alınmadı: hata.
Ölçüm tablosunun bir satırı, sunucudan gelen bir kayıtta birim alanı bulunmadığı için oluşturma sırasında bir istisna atsın. Elle yazılmış bir arayüzde bu, o satırın boş kalmasıdır. Bildirimsel bir ağaçta yanıt daha serttir: varsayılan davranış, ağacın tamamının sökülüp ekranın boşalmasıdır. Bu ders önce bu davranışın gerekçesini kurar, sonra hatayı bir alt ağaçta tutmanın yolunu, en sonda da bu yolun kapsamadığı hata türlerini gösterir.
Yarım Ağaç Neden Bırakılmaz
Uzlaşma, bir oluşturmanın ürettiği ağacın tamamını bir öncekiyle karşılaştırır ve farkı tek bir yazma aşamasında uygular. Ortada bir istisna atıldığında elde iki şey vardır: kısmen hesaplanmış yeni bir ağaç ve belgede duran eski ağaç.
Çalışma zamanının bu noktada kısmi ağacı yazması, hiçbir bileşenin sözleşmesinin geçerliliğini bilmediği bir durumu ekrana koymak olur. Tablo başlığı yeni süzgece göre “sıcaklık ölçümleri” der, satırlar eski süzgeçten kalmış nem değerlerini gösterir. Bir ölçüm istasyonu sayfasında bu, boş bir ekrandan daha kötüdür: kullanıcı yanlış veriyi doğru sanır.
Ayrıca hatanın nereye kadar yayıldığı bilinmez. Atan bileşen bir yan etki kaydetmiş, bir kutuya yazmış, bir aboneliğin yarısını kurmuş olabilir. Söküm, bilinen tek tutarlı duruma — hiçbir şey — dönmektir.
Bu yüzden varsayılan katıdır ve bilinçlidir. Yumuşatmanın yolu, çalışma zamanına hangi alt ağacın başarısız olabileceğini ve o alt ağaç yerine ne gösterileceğini önceden söylemekten geçer.
Hata Sınırı
Alt ağacındaki oluşturma hatalarını yakalayıp yerine önceden belirlenmiş bir görünüm koyan bileşene hata sınırı (error boundary) denir. Koyduğu görünüme bu derste yedek görünüm (fallback) denecektir; Tarayıcı ve Web Platformu kursundaki yuvaların yedek içeriğiyle karıştırılmaması için ayrı bir ad kullanılmıştır.
Yayılma kuralı, Programlama Temelleri kursundaki istisna yayılımının aynısıdır: hata çağrı zincirinde yukarı çıkar ve onu yakalayan en yakın sınırda durur.
// hata-siniri.mjs — olusturma hatasinin en yakin sinira kadar yayilmasi const agac = (sinirlar, bozuk) => ({ ad: "sayfa", sinir: sinirlar.includes("sayfa"), cocuklar: [ { ad: "baslik", cocuklar: [] }, { ad: "suzgec-paneli", sinir: sinirlar.includes("suzgec-paneli"), cocuklar: [ { ad: "suzgec-listesi", cocuklar: [] }, ] }, { ad: "olcum-tablosu", sinir: sinirlar.includes("olcum-tablosu"), cocuklar: [ { ad: "satir-1", cocuklar: [] }, { ad: "satir-2", hata: bozuk ? "birim alani eksik" : null, cocuklar: [] }, { ad: "satir-3", cocuklar: [] }, ] }, ], }); // Donen sayi, ekranda kalan bilesen sayisidir: yakalanan alt agacin isi atilir. function olustur(d, kutuk) { if (d.sinir) { try { const p = d.cocuklar.map((c) => olustur(c, kutuk)); return { metin: `${d.ad}(${p.map((x) => x.metin).join(" ")})`, sayi: 1 + p.reduce((t, x) => t + x.sayi, 0) }; } catch (h) { kutuk.push(`${d.ad} yakaladi -> ${h.message}`); return { metin: `${d.ad}(YEDEK)`, sayi: 1 }; } } if (d.hata) throw new Error(`${d.ad}: ${d.hata}`); if (d.cocuklar.length === 0) return { metin: d.ad, sayi: 1 }; const p = d.cocuklar.map((c) => olustur(c, kutuk)); return { metin: `${d.ad}(${p.map((x) => x.metin).join(" ")})`, sayi: 1 + p.reduce((t, x) => t + x.sayi, 0) }; } const say = (d) => 1 + d.cocuklar.reduce((t, c) => t + say(c), 0); const TOPLAM = say(agac([], false)); const HEPSI = ["sayfa", "suzgec-paneli", "olcum-tablosu"]; const SENARYOLAR = [ ["uc sinir, bozuk kayit", HEPSI, true], ["yalniz sayfa siniri, bozuk kayit", ["sayfa"], true], ["hic sinir yok, bozuk kayit", [], true], ["uc sinir, kayit duzeltilmis", HEPSI, false], ]; for (const [baslik, sinirlar, bozuk] of SENARYOLAR) { const kutuk = []; console.log(baslik + ":"); let sonuc; try { sonuc = olustur(agac(sinirlar, bozuk), kutuk); } catch (h) { kutuk.push(`kimse yakalamadi -> ${h.message}`); sonuc = { metin: "(agac tumuyle sokuldu)", sayi: 0 }; } for (const s of kutuk) console.log(` ${s}`); console.log(` ekranda: ${sonuc.metin}`); console.log(` ekranda kalan bilesen: ${sonuc.sayi}/${TOPLAM}`); }
uc sinir, bozuk kayit: olcum-tablosu yakaladi -> satir-2: birim alani eksik ekranda: sayfa(baslik suzgec-paneli(suzgec-listesi) olcum-tablosu(YEDEK)) ekranda kalan bilesen: 5/8 yalniz sayfa siniri, bozuk kayit: sayfa yakaladi -> satir-2: birim alani eksik ekranda: sayfa(YEDEK) ekranda kalan bilesen: 1/8 hic sinir yok, bozuk kayit: kimse yakalamadi -> satir-2: birim alani eksik ekranda: (agac tumuyle sokuldu) ekranda kalan bilesen: 0/8 uc sinir, kayit duzeltilmis: ekranda: sayfa(baslik suzgec-paneli(suzgec-listesi) olcum-tablosu(satir-1 satir-2 satir-3)) ekranda kalan bilesen: 8/8
Aynı hata, sınır yerleşimine göre üç ayrı sonuç üretir.
Tablonun kendi sınırı varsa yalnız tablo yedek görünüme düşer; başlık ve süzgeç paneli ayakta kalır ve kullanılabilir durumdadır. Kullanıcı süzgeci değiştirip başka bir sorguyla yeniden deneyebilir.
Yalnız sayfa düzeyinde sınır varsa hata üç düzey yukarı çıkar ve bütün sayfa tek bir yedek görünüme iner. Hiç sınır yoksa ekranda hiçbir şey kalmaz.
Son senaryo bir noktayı vurgular: sınır, hata olmadığında hiçbir şey yapmaz. Görünmez bir maliyeti yoktur, yalnız hata anında devreye girer.
Sınırların Yerleştirilmesi
Çıktıdaki 5, 1 ve 0 sayıları yerleştirme kuralını verir: sınır, çökebilecek parçanın hemen üstüne konur, sayfanın en tepesine değil.
Uygulamada üç düzeyli bir yerleşim yeterlidir. Sayfanın en dışında bir son çare sınırı bulunur; hiçbir şey yakalamasa da beyaz ekran yerine bir ileti gösterir. Sayfanın her ana bölümü — süzgeç paneli, ölçüm tablosu, karşılaştırma panosu — kendi sınırını taşır; biri çökerken diğerleri çalışır. Dış veriye dayanan ve bağımsız yenilenebilen küçük parçalar, örneğin tek bir ölçüm rozeti, kendi sınırını taşıyabilir.
Ters uç da bir hatadır. Her bileşeni sınırla sarmalamak, çöken parçanın yerine sessizce küçük bir yedek koyar ve sayfa “çalışıyor” görünürken yarısı eksik olur. Sınır bir hata gizleme aracı değil, hasarı sınırlama aracıdır.
Sınırın Yakalayamadıkları
Sınır bir çağrı yığını mekanizmasıdır ve kapsamı bu yığınla sınırlıdır.
// yakalanamayan.mjs — sinirin kapsami cagri yiginiyla sinirlidir const yigin = []; const yiginDurumu = () => `yigin = [${yigin.join(" > ") || "bos"}]`; function sinir(ad, govde) { yigin.push(ad); try { return govde(); } catch (h) { console.log(` ${ad} YAKALADI -> ${h.message}`); return `${ad}(YEDEK)`; } finally { yigin.pop(); } } const bekleyenler = []; let isleyici = null; console.log("A. olusturma sirasinda atilan hata"); const cikti = sinir("tablo-siniri", () => { console.log(` govde calisiyor, ${yiginDurumu()}`); isleyici = () => { throw new Error("silme dugmesi isleyicisi patladi"); }; bekleyenler.push(["olcum yaniti", () => { throw new Error("ag yaniti bozuk") }]); throw new Error("satir-2: birim alani eksik"); }); console.log(` ekranda: ${cikti}`); console.log("B. olay isleyicisi: olusturma coktan bitti"); console.log(` ${yiginDurumu()}`); try { isleyici(); } catch (h) { console.log(` sinira ugramadi -> ${h.message}`); } console.log("C. eszamansiz geri cagirim: ayri bir tur"); for (const [ad, is] of bekleyenler) { console.log(` ${ad} calisiyor, ${yiginDurumu()}`); try { is(); } catch (h) { console.log(` sinira ugramadi -> ${h.message}`); } }
A. olusturma sirasinda atilan hata govde calisiyor, yigin = [tablo-siniri] tablo-siniri YAKALADI -> satir-2: birim alani eksik ekranda: tablo-siniri(YEDEK) B. olay isleyicisi: olusturma coktan bitti yigin = [bos] sinira ugramadi -> silme dugmesi isleyicisi patladi C. eszamansiz geri cagirim: ayri bir tur olcum yaniti calisiyor, yigin = [bos] sinira ugramadi -> ag yaniti bozuk
Üç bölümdeki yığın satırları farkı tek başına açıklar. Gövde çalışırken sınır yığındadır ve atılan hata ona uğrar. Olay işleyicisi çağrıldığında ve eşzamansız geri çağırım çalıştığında yığın boştur; sınırın koruma bloğu çoktan sonlanmıştır.
Bunun pratik sonucu, hata işlemenin iki ayrı yerde kurulmasıdır. Oluşturma hataları sınırla karşılanır. Olay işleyicilerindeki ve eşzamansız işlerdeki hatalar, o işi yapan kodun kendi içinde yakalanır ve sonucu duruma yazılır — bir hata iletisi durumu, bir yeniden deneme düğmesi. Aynı ayrım Eşzamansız JavaScript ve Çalışma Zamanı kursundaki yakalanmamış söz reddi için de geçerlidir.
Sınırın kapsamadığı iki durum daha vardır: sınırın kendi yedek görünümü hata atarsa hata bir üst sınıra çıkar, ve sunucu tarafında üretilen bir oluşturmanın hataları istemcideki sınıra uğramaz.
Kurtarma ve Bildirme
Yakalamak yetmez; yakalanan hatadan çıkış da tasarlanır.
Sınırın kendisi hata atan bileşenin üstünde olduğu için kendi durumu bozulmamıştır. Bu, kurtarmayı olanaklı kılar. En yaygın biçim bir yeniden deneme eylemidir: sınır, yedek görünümde bir düğme gösterir; düğme alt ağacın kimliğini değiştirerek onu baştan kurar. Kimliğin değişmesi önemlidir — aynı kimlikle yeniden çizmek, hataya yol açan durumu koruyup aynı hatayı üretir.
İkinci biçim yönlendirmedir: bozuk bir kayıt yüzünden ayrıntı görünümü çöküyorsa liste görünümüne dönmek, kullanıcıyı çalışan bir ekranda bırakır.
Bildirme iki ayrı okuyucuya yapılır. Geliştiriciye kütüğe yazılan kayıt gider: hata iletisi, yığıt izi, hangi bileşende oluştuğu, o anki yönlendirme adresi. Kullanıcıya ise ne yığıt izi ne hata kodu gösterilir; ne olduğunu ve ne yapabileceğini söyleyen bir cümle yeterlidir. Yedek görünümün de erişilebilir olması gerekir: iletinin okuyucuya duyurulması ve odağın yeniden deneme düğmesine taşınması, Web’in Temelleri ve HTML kursundaki odak yönetimi kurallarına uyar.
Özet
- Oluşturma ortasında atılan bir hata yarım bir ağaç bırakır; kısmi ağacı yazmak tutarsız bir ekran üretir, bu yüzden varsayılan davranış ağacı sökmektir.
- Hata sınırı, alt ağacındaki oluşturma hatalarını yakalayıp yerine yedek görünüm koyan bileşendir; hata en yakın sınırda durur.
- Sınır yerleşimi ekranda kalan bileşen sayısını belirler: bölüm düzeyinde sınır sayfanın geri kalanını kullanılabilir bırakır, yalnız sayfa düzeyinde sınır bırakmaz.
- Sınır bir çağrı yığını mekanizmasıdır; olay işleyicilerinde, zamanlayıcılarda ve eşzamansız geri çağırımlarda atılan hatalar kapsamı dışındadır ve orada yakalanır.
- Kurtarma, alt ağacın kimliğini değiştirerek yeniden kurmaktır; aynı kimlikle yeniden oluşturmak aynı hatayı üretir.
- Kütüğe ayrıntı, kullanıcıya tek cümle ve bir eylem gider; yedek görünüm de erişilebilir olmalıdır.
Sonraki Adım
Hata sınırı, bir alt ağacın başarısız olduğu durumu ağacın geri kalanından ayırır. Aynı biçimde ayrılması gereken ikinci bir durum vardır: alt ağacın henüz hazır olmadığı durum. Ölçüm tablosu, veriler sunucudan gelene kadar çizilemez; karşılaştırma panosu ikinci istasyonun kayıtlarını bekler. Bunu her bileşende ayrı bir “yükleniyor” bayrağıyla yönetmek, birbiriyle çelişebilen durum bileşimleri üretir ve iç içe beklemelerde her düzeyin ayrı bir gösterge çevirmesine yol açar. Sonraki ders, hata sınırıyla aynı yukarı doğru sinyal mekanizmasının bekleme için nasıl kullanıldığını ve yükleniyor görünümlerinin nerede toplanacağını ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.