Programlama konusunda ne kadar iyi olursak olalım, bazen kodlarımızda hatalar olabilir. Bu hatalar bizim hatalarımızdan, beklenmedik bir kullanıcı girdisinden, hatalı bir sunucu yanıtından ve daha binlerce nedenden kaynaklanabilir.
Genelde kodda bir hata olduğunda yazdığımız kod bir adım ileriye gidemeden sona erer ve konsola bunun nedenini yazar.
Ancak try…catch sözdizimi yapısı hataları “yakalamamızı” sağlar, böylece kodun ölmesi yerine daha makul bir şey yaptırabiliriz.
“try…catch” yazımı
try...catch yapısı iki ana bloktan oluşur: try (dene) ve sonrasında catch (yakala):
try {
// kod...
} catch (err) {
// hata yönetimi.
}
Şu şekilde çalışır:
- Önce
try {...}içerisindekiler çalıştırılır. - Eğer hata yoksa
catch(err)görmezden gelinir: çalışma try’ın sonuna ulaşır ve sonracatch’i atlar. - Eğer hata meydana gelirse,
try’ın çalışması durdurulur vecatch(err)çalışmaya başlar. Buradakierrdeğişkeni "ne oldu da hata meydana geldi"ye dair detayları tutan bir objedir.
Öyleyse try {...} içerisindeki kod doğrudan sona eremez, bize catch içerisinde bunu idare etmemiz için olanak sağlar.
Birkaç örnek inceleyelim.
-
Hatasız örnek:
alert(1)ve(2)'yi gösterir:try { alert("try başladı"); // (1) <-- // ...no errors here alert("try bitti"); // (2) <-- } catch (err) { alert("Catch görmezden gelindi çünkü bir hata meydana gelmedi."); // (3) } alert("...Kod normal çalışmasına devam etti."); -
Hatalı örnek:
(1)ve(3)'ü gösterir:try { alert('try başladı'); // (1) <-- lalala; // hata, değişken tanımlı değil! alert('try bitti (Hiç erişilemedi)'); // (2) } catch(err) { alert(`Hata meydana geldi!`); // (3) <-- } alert("...Kod normal çalışmasına devam etti.");
try...catchsadece çalışma zamanlı hatalar içindirEğer kod yazımsal olarak hatalıysa çalışmayacaktır, örneğin süslü parantezler açılmış ama kapatılmamışsa:
try {
{{{{{{{{{{{{
} catch(e) {
alert("JavaScript motoru bunu anlayamaz, çünkü geçerli bir kod değildir.");
}
JavaScript motoru önce kodu okur, sonra çalıştırır. Eğer hata okuma aşamasında meydana gelirse bunlara “ayrıştırma-zamanı” hataları denir ve kurtarılamaz hatalardır. Bundan dolayı JavaScript motoru bunları anlayamaz.
Bundan dolayı try...catch ancak ve ancak geçerli kodlarda oluşacak hataları idare edebilir. Bu hatalara “çalışma zamanı hataları” veya bazen “istisnalar” (exception) denilmektedir.
try...catch Senkronize olarak çalışmaktadırEğer “zamanlanmış” bir kodda, setTimeout gibi, bir hata meydana gelirse try...catch bunu yakalayamaz:
try {
setTimeout(function() {
noSuchVariable; // kod burada ölecektir.
}, 1000);
} catch (e) {
alert( "çalışmaz" );
}
Bunun nedeni try...catch’in aslında fonksiyonu zamanlayan setTimeout’u kapsamasıdan dolayıdır. Fakat fonksiyon daha sonra çalışır. O anda aslında motor try...catchi geçmiş olur.
Eğer zamanlanmış fonksiyon içerisinde bu hatayı yakalamak istiyorsanız, try...catch bloğunu fonksiyonun içerisine yazmalısınız:
setTimeout(function() {
try {
noSuchVariable; // try...catch hataları yakalayacaktır.
} catch (e) {
alert( "hata burada yakalandı!" );
}
}, 1000);
Hata Objesi
Hata meydana geldiğinde, JavaScript bu hata ile ilgili bir obje yaratır. Sonrasında bu obje catch’e argüman olarak gönderilir:
try {
// ...
} catch (err) {
// <-- the "error object", could use another word instead of err
// ...
}
Tüm varsayılan hatalar için, catch içerisinde hata objesi iki ana özelliği taşır:
isim(name)- Hata ismi. Tanımsız değerler için bu
"ReferenceError"'dur. mesaj(message)- Hatanın detayları hakkında anlaşılır bilgi verir.
Çoğu ortamda standart olmayan başka özellikler de bulunmaktadır. Bunlardan en fazla kullanılan ve desteklenen:
stack- O anki çağrı yığını: Hataya neden olan fonksiyon zincirini belirtir. Genelde hata ayıklama amacıyla kullanılır.
Örneğin:
try {
lalala; // hata, değişken tanımlı değil!
} catch(err) {
alert(err.name); // ReferenceError
alert(err.message); // lalala tanımlı değil
alert(err.stack); // ReferenceError: lalala şurada tanımlanmadı ...
// ayrıca hatayı tümüyle göstermek de mümkündür.
// hata karakter dizisine "name:message" gibi çevirildi.
alert(err); // ReferenceError: lalala tanımlı değil
}
try...catch kullanımı
Gerçek hayatta try...catch’in nasıl kullanılabileceğine bakalım.
Bildiğiniz gibi, JavaScript JSON.parse(str) metodu sayesinde JSON olarak tanımlanmış değerlerin okunmasına olanak tanır.
Genelde ağ üzerinden başka bir serverdan veya kaynaktan gelen verinin okunmasında kullanılır.
Bu veriyi aldıktan sonra JSON.parse ile şu şekilde okuyabiliriz:
let json = '{"name":"John", "age": 30}'; // sunucudan gelen veri.
let user = JSON.parse(json); // bu veriyi JS objesine dönüştür.
//Artık user karakter dizisinden oluşan objelere sahiptir.
alert( user.name ); // John
alert( user.age ); // 30
JSON hakkında daha derin bilgiyi JSON metodları, toJSON bölümünden öğrenebilirsiniz.
Eğer json düzgün gelmiyorsa JSON.parse hata üretir ve kod anında “ölür”.
Bunun ile yetinmeli miyiz? Elbette hayır.
Bu şekliyle eğer gelen veride bir hata varsa ziyaretçi nerede yanlış olduğunu bilemeyecektir. İnsanlar hata olduğunda herhangi bir hata mesajı almadan öylece ölen bir şeyden nefret ederler.
Bunun çözümü için try...catch kullanılabilir:
let json = "{ bad json }";
try {
let user = JSON.parse(json); // <-- when an error occurs...
alert( user.name ); // doesn't work
} catch (e) {
// ...çalışma buradan devam eder.
alert( "Kusura bakmayın, veride hata var. Talep tekrar yapacaktır" );
alert( e.name );
alert( e.message );
}
Burada catch bloğu sadece mesajı göstermek için kullanılmıştır. Fakat burada ağ talebi, kullanıcıya başka bir yöntem sunma, loglama için hata loginin tutulması gibi işlemler yapılabilir.
Kendi hatalarımızı atma
Diyelim ki json yazım olarak doğru da "name" özelliğini olması gerekirken yoksa ?
Aşağıdaki gibi: