← Kursa Dön
📄 Text · 30 min

Hata Yönetimi

Giriş — Hatalar Kaçınılmazdır

Hiçbir program mükemmel değildir. Kullanıcı beklediğiniz formatta veri girmez, API sunucusu cevap vermez, dosya bulunamaz, ağ bağlantısı kopar. Hata yönetimi, programınızın bu beklenmedik durumlarla zarif bir şekilde başa çıkmasını sağlar — çökme yerine, kullanıcıya anlamlı bir mesaj gösterir veya alternatif bir yol izler.

Hata yönetimi, "hatanın olmaması" değil, "hata olduğunda ne yapılacağının planlanması"dır. Tıpkı bir binanın depreme dayanıklı inşa edilmesi gibi — deprem olmasını engelleyemezsiniz, ama binanın ayakta kalmasını sağlayabilirsiniz.

Analoji: Hata yönetimini uçak kokpitindeki alarm sistemi gibi düşünün. Pilot her türlü acil durumu önceden planlar: motor arızası, kötü hava, yakıt sorunu. Alarm çaldığında panikle çökmek yerine, önceden belirlenmiş prosedürler devreye girer. Programlarınızda da aynı mantık geçerlidir — "bu fonksiyon başarısız olursa ne yapacağım?" sorusunu yazarken sorun, çalışırken değil.


try / catch / finally

JavaScript'te hata yönetiminin temel mekanizması try/catch/finally yapısıdır.

Temel Kullanım

try {
  // Hata oluşabilecek kod buraya yazılır
  let sonuc = riskliFonksiyon();
  console.log(sonuc);
} catch (error) {
  // Hata oluşursa bu blok çalışır
  console.error("Bir hata oluştu:", error.message);
} finally {
  // Hata olsun veya olmasın HER ZAMAN çalışır
  console.log("İşlem tamamlandı.");
}

Detaylı Örnek

function bolme(a, b) {
  if (typeof a !== "number" || typeof b !== "number") {
    throw new Error("Parametreler sayı olmalıdır");
  }
  if (b === 0) {
    throw new Error("Sıfıra bölme yapılamaz");
  }
  return a / b;
}

// Hata yönetimi ile güvenli kullanım
try {
  console.log(bolme(10, 2));   // 5
  console.log(bolme(10, 0));   // Hata fırlatır!
  console.log("Bu satır çalışmaz"); // Hata sonrası atlanır
} catch (error) {
  console.error(`Hata yakalandı: ${error.message}`);
  // "Hata yakalandı: Sıfıra bölme yapılamaz"
} finally {
  console.log("Hesaplama denemesi bitti.");
}

console.log("Program devam ediyor"); // Çalışır — program çökmedi

Önemli noktalar:

  • try bloğunda hata oluşursa, hatadan sonraki satırlar çalışmaz

  • catch bloğu sadece hata oluşursa çalışır

  • finally bloğu her durumda çalışır (hata olsun, olmasın, return olsun)

  • catch olmadan sadece try/finally kullanılabilir (ama önerilmez)

finally'nin Garantisi

finally bloğu, return ifadesi bile olsa çalışır:

function veriIsle() {
  try {
    console.log("Veri işleniyor...");
    return "Başarılı"; // return olsa bile finally çalışır
  } catch (error) {
    return "Hata";
  } finally {
    console.log("Temizlik yapılıyor..."); // HER ZAMAN çalışır
    // Dosya kapatma, bağlantı kesme gibi işlemler burada yapılır
  }
}

let sonuc = veriIsle();
// Konsol:
// "Veri işleniyor..."
// "Temizlik yapılıyor..."
console.log(sonuc); // "Başarılı"

İç İçe (Nested) try/catch

function veriGetir(url) {
  try {
    // Dış try — genel hata yönetimi
    let veri;

    try {
      // İç try — spesifik hata yönetimi
      veri = JSON.parse('{"isim": "Ali"}');
    } catch (parseError) {
      console.error("JSON parse hatası:", parseError.message);
      veri = {}; // Varsayılan değer
    }

    // Veri ile işlem yap
    if (!veri.isim) {
      throw new Error("İsim alanı eksik");
    }

    return veri;
  } catch (error) {
    console.error("Genel hata:", error.message);
    return null;
  }
}

💡 İpucu: İç içe try/catch'leri minimumda tutun. Genellikle farklı hata durumlarını aynı catch bloğunda, hata tipine göre ayırt etmek daha temizdir.


throw — Hata Fırlatma

throw ifadesi, kendi hatalarınızı oluşturmanızı sağlar. Herhangi bir değer fırlatılabilir, ama her zaman Error nesnesi kullanın:

// ✅ Doğru — Error nesnesi fırlat
throw new Error("Bir şeyler ters gitti");

// ❌ Teknik olarak çalışır ama YAPMAYIN
// throw "Hata mesajı";          // String fırlatmak — stack trace yok!
// throw 404;                     // Sayı fırlatmak — anlamsız
// throw { mesaj: "hata" };       // Nesne — Error değil

Neden her zaman `Error` nesnesi kullanmalısınız?

Error nesnesi üç kritik bilgi taşır:

  • message — Hata mesajı

  • name — Hata türü (Error, TypeError, vs.)

  • stack — Stack trace (hatanın nerede oluştuğu)

try {
  throw new Error("Detaylı hata mesajı");
} catch (error) {
  console.log(error.message); // "Detaylı hata mesajı"
  console.log(error.name);    // "Error"
  console.log(error.stack);   // Hatanın tam yolu (debugging için çok değerli)
  // Error: Detaylı hata mesajı
  //     at Object.<anonymous> (dosya.js:2:9)
  //     at Module._compile (module.js:653:30)
  //     ...
}

Koşullu Hata Fırlatma

function kayitOlustur(kullanici) {
  // Validasyon — geçersiz durumları erken yakala
  if (!kullanici) {
    throw new Error("Kullanıcı bilgisi gereklidir");
  }

  if (!kullanici.email) {
    throw new Error("E-posta adresi zorunludur");
  }

  if (!kullanici.email.includes("@")) {
    throw new Error("Geçerli bir e-posta adresi giriniz");
  }

  if (kullanici.yas !== undefined && kullanici.yas < 13) {
    throw new Error("Kayıt için en az 13 yaşında olmalısınız");
  }

  // Validasyon geçti — kayıt işlemi
  return {
    ...kullanici,
    id: Math.random().toString(36).substr(2, 9),
    kayitTarihi: new Date()
  };
}

// Kullanım
try {
  let yeniKullanici = kayitOlustur({
    isim: "Ali",
    email: "ali",
    yas: 10
  });
} catch (error) {
  console.error(`Kayıt hatası: ${error.message}`);
  // "Kayıt hatası: Geçerli bir e-posta adresi giriniz"
}

Error Türleri

JavaScript'te birkaç yerleşik (built-in) hata türü vardır. Her biri farklı bir sorunu temsil eder:

ReferenceError — Tanımsız Değişken

Var olmayan bir değişkene erişmeye çalıştığınızda oluşur:

try {
  console.log(tanimsizDegisken);
} catch (error) {
  console.log(error.name);    // "ReferenceError"
  console.log(error.message); // "tanimsizDegisken is not defined"
}

// Yaygın senaryo
try {
  let sonuc = hesaplaFiyat(100); // hesaplaFiyat tanımlı değil
} catch (error) {
  if (error instanceof ReferenceError) {
    console.error("Fonksiyon bulunamadı:", error.message);
  }
}

TypeError — Yanlış Tip Kullanımı

Bir değerin beklenen tipte olmaması durumunda oluşur:

try {
  null.toString();        // null'ın metodu yok
} catch (error) {
  console.log(error.name); // "TypeError"
}

try {
  let sayi = 42;
  sayi();                 // Sayı fonksiyon olarak çağrılamaz
} catch (error) {
  console.log(error.name); // "TypeError"
}

try {
  const obj = Object.freeze({ isim: "Ali" });
  obj.isim = "Veli";      // Strict mode'da TypeError
} catch (error) {
  console.log(error.name); // "TypeError"
}

SyntaxError — Sözdizimi Hatası

Kod yazım kurallarına uymadığında oluşur. Genellikle try/catch ile yakalanamaz çünkü kod parse edilirken oluşur. Ama JSON.parse veya eval gibi runtime parsing durumlarında yakalanabilir:

try {
  JSON.parse("{ geçersiz json }");
} catch (error) {
  console.log(error.name);    // "SyntaxError"
  console.log(error.message); // "Unexpected token g in JSON at position 2"
}

// Kullanıcıdan gelen JSON verisi
function guvenliJsonParse(jsonString) {
  try {
    return { basarili: true, veri: JSON.parse(jsonString) };
  } catch (error) {
    return { basarili: false, hata: `Geçersiz JSON: ${error.message}` };
  }
}

console.log(guvenliJsonParse('{"isim": "Ali"}'));
// { basarili: true, veri: { isim: "Ali" } }

console.log(guvenliJsonParse('bozuk veri'));
// { basarili: false, hata: "Geçersiz JSON: Unexpected token b..." }

RangeError — Aralık Dışı

Bir değer izin verilen aralığın dışında olduğunda oluşur:

try {
  let dizi = new Array(-1); // Negatif uzunluk!
} catch (error) {
  console.log(error.name); // "RangeError"
  console.log(error.message); // "Invalid array length"
}

try {
  let sayi = 1;
  sayi.toFixed(200); // Maximum 100
} catch (error) {
  console.log(error.name); // "RangeError"
}

// Sonsuz recursion
try {
  function sonsuz() { sonsuz(); }
  sonsuz();
} catch (error) {
  console.log(error.name); // "RangeError"
  console.log(error.message); // "Maximum call stack size exceeded"
}

URIError — URI Hatası

try {
  decodeURIComponent("%"); // Geçersiz URI
} catch (error) {
  console.log(error.name); // "URIError"
}

Hata Tipine Göre Ayrıştırma

function veriIsle(girdi) {
  try {
    let veri = JSON.parse(girdi);
    let sonuc = veri.deger.toUpperCase();
    return sonuc;
  } catch (error) {
    // Hata tipine göre farklı müdahale
    if (error instanceof SyntaxError) {
      console.error("JSON formatı geçersiz");
    } else if (error instanceof TypeError) {
      console.error("Veri yapısı beklenenden farklı");
    } else {
      console.error("Beklenmedik hata:", error.message);
    }
    return null;
  }
}

veriIsle("geçersiz json");           // "JSON formatı geçersiz"
veriIsle('{"deger": null}');          // "Veri yapısı beklenenden farklı"
veriIsle('{"deger": "merhaba"}');     // "MERHABA"

⚠️ Dikkat: instanceof ile hata tipini kontrol etmek, error.name ile string karşılaştırmasından daha güvenlidir. instanceof kalıtım zincirini de kontrol eder.


Custom Errors (Özel Hata Sınıfları)

Yerleşik hata türleri her durumu kapsamaz. Kendi hata sınıflarınızı oluşturarak daha anlamlı ve spesifik hata yönetimi yapabilirsiniz:

// Özel hata sınıfı — Error'dan türetilir
class ValidasyonHatasi extends Error {
  constructor(alan, mesaj) {
    super(mesaj); // Üst sınıfın constructor'ını çağır
    this.name = "ValidasyonHatasi";
    this.alan = alan;
  }
}

class YetkilendirmeHatasi extends Error {
  constructor(mesaj = "Bu işlem için yetkiniz yok") {
    super(mesaj);
    this.name = "YetkilendirmeHatasi";
    this.kod = 403;
  }
}

class BulunamadiHatasi extends Error {
  constructor(kaynak, id) {
    super(`${kaynak} #${id} bulunamadı`);
    this.name = "BulunamadiHatasi";
    this.kod = 404;
    this.kaynak = kaynak;
    this.id = id;
  }
}

// Kullanım
function kullaniciBul(id) {
  const kullanicilar = [
    { id: 1, isim: "Ali", rol: "admin" },
    { id: 2, isim: "Ayşe", rol: "user" }
  ];

  const kullanici = kullanicilar.find(k => k.id === id);

  if (!kullanici) {
    throw new BulunamadiHatasi("Kullanıcı", id);
  }

  return kullanici;
}

function kullaniciSil(id, isteyenRol) {
  if (isteyenRol !== "admin") {
    throw new YetkilendirmeHatasi("Kullanıcı silme yetkisi sadece admin'lerdedir");
  }

  const kullanici = kullaniciBul(id);
  // Silme işlemi...
  return `${kullanici.isim} silindi`;
}

// Kapsamlı hata yönetimi
try {
  let sonuc = kullaniciSil(99, "user");
  console.log(sonuc);
} catch (error) {
  if (error instanceof YetkilendirmeHatasi) {
    console.error(`🔒 Yetki hatası (${error.kod}): ${error.message}`);
  } else if (error instanceof BulunamadiHatasi) {
    console.error(`🔍 Bulunamadı (${error.kod}): ${error.message}`);
  } else if (error instanceof ValidasyonHatasi) {
    console.error(`📝 Validasyon hatası [${error.alan}]: ${error.message}`);
  } else {
    console.error(`❌ Beklenmedik hata: ${error.message}`);
    // Beklenmedik hataları loglama servisine gönder
  }
}

Hata Sınıfı Hiyerarşisi

// Uygulamaya özel hata hiyerarşisi
class UygulamaHatasi extends Error {
  constructor(mesaj, kod) {
    super(mesaj);
    this.name = "UygulamaHatasi";
    this.kod = kod;
    this.zaman = new Date();
  }
}

class ApiHatasi extends UygulamaHatasi {
  constructor(endpoint, statusKod, mesaj) {
    super(mesaj, statusKod);
    this.name = "ApiHatasi";
    this.endpoint = endpoint;
  }
}

class VeritabaniHatasi extends UygulamaHatasi {
  constructor(sorgu, mesaj) {
    super(mesaj, 500);
    this.name = "VeritabaniHatasi";
    this.sorgu = sorgu;
  }
}

// Hiyerarşi avantajı — instanceof ile genel kontrol
try {
  throw new ApiHatasi("/users", 404, "Endpoint bulunamadı");
} catch (error) {
  console.log(error instanceof ApiHatasi);      // true
  console.log(error instanceof UygulamaHatasi); // true — kalıtım!
  console.log(error instanceof Error);          // true — tüm hatalar Error'dan türer
}

Defensive Programming (Savunmacı Programlama)

Savunmacı programlama, hataları oluşmadan önce önlemeye odaklanır. "En iyi hata, hiç oluşmayan hatadır."

Input Validation (Girdi Doğrulama)

// ❌ Savunmasız — her şey patlar
function indirimHesapla(fiyat, indirimYuzde) {
  return fiyat * (1 - indirimYuzde / 100);
}

console.log(indirimHesapla("yüz", "on")); // NaN

// ✅ Savunmacı — her duruma hazır
function indirimHesaplaGuvenli(fiyat, indirimYuzde) {
  // Tip kontrolü
  if (typeof fiyat !== "number" || isNaN(fiyat)) {
    throw new ValidasyonHatasi("fiyat", "Fiyat geçerli bir sayı olmalıdır");
  }
  if (typeof indirimYuzde !== "number" || isNaN(indirimYuzde)) {
    throw new ValidasyonHatasi("indirimYuzde", "İndirim yüzdesi bir sayı olmalıdır");
  }

  // Aralık kontrolü
  if (fiyat < 0) {
    throw new ValidasyonHatasi("fiyat", "Fiyat negatif olamaz");
  }
  if (indirimYuzde < 0 || indirimYuzde > 100) {
    throw new ValidasyonHatasi("indirimYuzde", "İndirim %0-%100 arasında olmalıdır");
  }

  return Number((fiyat * (1 - indirimYuzde / 100)).toFixed(2));
}

try {
  console.log(indirimHesaplaGuvenli(100, 20)); // 80
  console.log(indirimHesaplaGuvenli(-50, 20)); // Hata!
} catch (error) {
  console.error(`${error.alan}: ${error.message}`);
}

Guard Clauses (Koruma İfadeleri)

// Guard clauses ile temiz validasyon
function siparisOlustur(sepet, kullanici, adres) {
  // Guard clauses — başta kontrol et, erken dön
  if (!sepet || !Array.isArray(sepet) || sepet.length === 0) {
    throw new ValidasyonHatasi("sepet", "Sepet boş olamaz");
  }

  if (!kullanici?.id) {
    throw new YetkilendirmeHatasi("Sipariş için giriş yapmalısınız");
  }

  if (!adres?.sehir || !adres?.adresSatiri) {
    throw new ValidasyonHatasi("adres", "Teslimat adresi eksik");
  }

  // Tüm kontroller geçildi — güvenli alan
  const toplam = sepet.reduce((acc, urun) => acc + urun.fiyat * urun.adet, 0);

  return {
    id: Date.now(),
    kullaniciId: kullanici.id,
    urunler: sepet,
    toplam,
    adres,
    durum: "beklemede"
  };
}

Null/Undefined Güvenliği

// Optional chaining ve nullish coalescing ile güvenli erişim
function kullaniciProfiliGoster(kullanici) {
  const isim = kullanici?.isim ?? "Anonim";
  const avatar = kullanici?.profil?.avatar ?? "/default-avatar.png";
  const takipciSayisi = kullanici?.istatistikler?.takipci ?? 0;
  const bio = kullanici?.profil?.bio?.slice(0, 100) ?? "Henüz bio eklenmemiş";

  return `
    İsim: ${isim}
    Avatar: ${avatar}
    Takipçi: ${takipciSayisi}
    Bio: ${bio}
  `;
}

// null, undefined, eksik alanlar — hiçbiri hata vermez
console.log(kullaniciProfiliGoster(null));
console.log(kullaniciProfiliGoster({}));
console.log(kullaniciProfiliGoster({ isim: "Ali" }));

Error Handling Patterns (Hata Yönetimi Kalıpları)

Pattern 1: Result Object (Sonuç Nesnesi)

Hata fırlatmak yerine, başarı/hata durumunu bir nesne olarak döndürmek:

// try/catch gerektirmeyen yaklaşım
function kullaniciDogrula(email, sifre) {
  if (!email || !email.includes("@")) {
    return { ok: false, hata: "Geçersiz e-posta" };
  }

  if (!sifre || sifre.length < 8) {
    return { ok: false, hata: "Şifre en az 8 karakter olmalı" };
  }

  // Simüle veritabanı kontrolü
  if (email === "ali@test.com" && sifre === "sifre12345") {
    return { ok: true, veri: { id: 1, isim: "Ali", email } };
  }

  return { ok: false, hata: "E-posta veya şifre yanlış" };
}

// Kullanım — temiz ve basit
const sonuc = kullaniciDogrula("ali@test.com", "sifre12345");

if (sonuc.ok) {
  console.log(`Hoş geldin, ${sonuc.veri.isim}!`);
} else {
  console.error(`Giriş hatası: ${sonuc.hata}`);
}

Pattern 2: Error Boundary (Hata Sınırı)

Üst seviyede tüm hataları yakalayan bir yapı:

// Uygulama seviyesinde hata yakalayıcı
function uygulamaCalistir(fonksiyon) {
  try {
    return fonksiyon();
  } catch (error) {
    // Hata tipine göre işlem
    if (error instanceof ValidasyonHatasi) {
      console.error(`📝 Validasyon: [${error.alan}] ${error.message}`);
    } else if (error instanceof YetkilendirmeHatasi) {
      console.error(`🔒 Yetki: ${error.message}`);
      // Kullanıcıyı giriş sayfasına yönlendir
    } else if (error instanceof BulunamadiHatasi) {
      console.error(`🔍 Bulunamadı: ${error.message}`);
      // 404 sayfası göster
    } else {
      // Beklenmedik hata — loglama servisine gönder
      console.error(`🔥 Kritik hata: ${error.message}`);
      console.error(error.stack);
      // logServisineGonder(error);
    }

    return null;
  }
}

// Kullanım
let sonuc2 = uygulamaCalistir(() => {
  let kullanici = kullaniciBul(99);
  return kullaniciSil(99, "admin");
});

Pattern 3: Retry (Yeniden Deneme)

Geçici hatalarda işlemi otomatik tekrarlama:

function yenidenDene(fonksiyon, maxDeneme = 3, beklemeMs = 1000) {
  let sonHata;

  for (let deneme = 1; deneme <= maxDeneme; deneme++) {
    try {
      console.log(`Deneme ${deneme}/${maxDeneme}...`);
      return fonksiyon();
    } catch (error) {
      sonHata = error;
      console.warn(`Deneme ${deneme} başarısız: ${error.message}`);

      if (deneme < maxDeneme) {
        // Basit bekleme simülasyonu (gerçekte async olmalı)
        const beklemeSuresi = beklemeMs * deneme; // Her denemede artan bekleme
        console.log(`${beklemeSuresi}ms sonra tekrar deneniyor...`);
      }
    }
  }

  throw new Error(`${maxDeneme} denemeden sonra başarısız: ${sonHata.message}`);
}

// Kullanım
let denemeSayisi = 0;

try {
  let sonuc3 = yenidenDene(() => {
    denemeSayisi++;
    if (denemeSayisi < 3) {
      throw new Error("Sunucu yanıt vermiyor");
    }
    return { veri: "Başarılı!" };
  });
  console.log(sonuc3); // 3. denemede başarılı
} catch (error) {
  console.error("Tüm denemeler başarısız:", error.message);
}

Gerçek Dünya Örneği: Ayar Dosyası Yükleyici

// Birden fazla kaynaktan ayar yükleme sistemi
class AyarYuklemeHatasi extends Error {
  constructor(kaynak, orijinalHata) {
    super(`Ayarlar ${kaynak} kaynağından yüklenemedi`);
    this.name = "AyarYuklemeHatasi";
    this.kaynak = kaynak;
    this.orijinalHata = orijinalHata;
  }
}

function ayarlariYukle() {
  const kaynaklar = [
    { isim: "ortam değişkenleri", yukle: () => ortamDegiskenleriniOku() },
    { isim: "config.json", yukle: () => configDosyasiniOku() },
    { isim: "varsayılan ayarlar", yukle: () => varsayilanAyarlar() }
  ];

  const hatalar = [];
  let ayarlar = {};

  for (const kaynak of kaynaklar) {
    try {
      const yeniAyarlar = kaynak.yukle();
      ayarlar = { ...ayarlar, ...yeniAyarlar };
      console.log(`✅ ${kaynak.isim} yüklendi`);
    } catch (error) {
      const hata = new AyarYuklemeHatasi(kaynak.isim, error);
      hatalar.push(hata);
      console.warn(`⚠️ ${kaynak.isim} yüklenemedi: ${error.message}`);
    }
  }

  // Kritik ayarları doğrula
  const zorunluAlanlar = ["port", "veritabaniUrl"];
  const eksikler = zorunluAlanlar.filter(alan => !(alan in ayarlar));

  if (eksikler.length > 0) {
    throw new ValidasyonHatasi(
      "ayarlar",
      `Zorunlu ayarlar eksik: ${eksikler.join(", ")}`
    );
  }

  if (hatalar.length > 0) {
    console.warn(`⚠️ ${hatalar.length} kaynak yüklenemedi, varsayılanlar kullanılıyor`);
  }

  return ayarlar;
}

// Yardımcı fonksiyonlar (simüle)
function ortamDegiskenleriniOku() {
  return { port: 3000, ortam: "development" };
}

function configDosyasiniOku() {
  // Simüle: dosya bulunamadı
  throw new Error("ENOENT: config.json bulunamadı");
}

function varsayilanAyarlar() {
  return {
    veritabaniUrl: "mongodb://localhost:27017/test",
    logSeviyesi: "info",
    maxBaglanti: 10
  };
}

// Çalıştır
try {
  const config = ayarlariYukle();
  console.log("\n📋 Son ayarlar:", config);
} catch (error) {
  console.error(`🔥 Uygulama başlatılamıyor: ${error.message}`);
  // process.exit(1); // Node.js'te uygulamayı durdur
}

Best Practices (En İyi Pratikler)

// 1. Spesifik hata yakalayın — genel catch kullanmaktan kaçının
// ❌
try { /* ... */ } catch (e) { console.log("Hata oldu"); }

// ✅
try { /* ... */ } catch (error) {
  if (error instanceof TypeError) {
    // Spesifik müdahale
  } else {
    throw error; // Beklenmeyen hatayı yeniden fırlat
  }
}

// 2. Hataları yutmayın (sessizce görmezden gelmeyin)
// ❌ Sessizce yutma
try { riskliFonksiyon(); } catch (e) { /* hiçbir şey yapma */ }

// ✅ En azından logla
try { riskliFonksiyon(); } catch (error) {
  console.error("riskliFonksiyon hatası:", error);
}

// 3. catch'te çok fazla iş yapmayın
// Sadece hatayı yönetin, iş mantığını catch'e koymayın

// 4. Asla throw ile string fırlatmayın
// ❌ throw "bir hata oluştu";
// ✅ throw new Error("bir hata oluştu");

// 5. finally'yi temizlik için kullanın
let baglanti = null;
try {
  baglanti = veritabaniBaglan();
  // İşlemler...
} catch (error) {
  console.error(error);
} finally {
  // Hata olsa da olmasa da bağlantıyı kapat
  if (baglanti) {
    baglanti.kapat();
  }
}

Özet

  • 🔹 try/catch/finally, JavaScript'in temel hata yönetim mekanizmasıdır. finally her durumda çalışır — temizlik işlemleri için idealdir

  • 🔹 throw ile kendi hatalarınızı fırlatabilirsiniz — her zaman Error nesnesi (veya alt sınıfı) kullanın, string fırlatmayın

  • 🔹 Yerleşik hata türleri: ReferenceError (tanımsız değişken), TypeError (yanlış tip), SyntaxError (sözdizimi), RangeError (aralık dışı)

  • 🔹 Custom Error sınıfları (extends Error) ile uygulamanıza özgü, anlamlı hata tipleri oluşturun — instanceof ile ayırt edin

  • 🔹 Defensive programming: Hataları oluşmadan önleyin — input validation, guard clauses, optional chaining, nullish coalescing

  • 🔹 Hataları asla yutmayın (boş catch bloğu) — en azından loglayın; beklenmedik hataları yeniden fırlatın (throw error)