JavaScript'teki Hataların İşlenmesi İçin Kesin Bir Kılavuz
Yayınlanan: 2022-01-24Murphy kanunu, ters gidebilecek her şeyin eninde sonunda ters gideceğini belirtir. Bu, programlama dünyasında biraz fazla iyi geçerlidir. Bir uygulama oluşturursanız, hatalar ve başka sorunlar yaratma ihtimaliniz yüksektir. JavaScript'teki hatalar böyle yaygın bir sorundur!
Bir yazılım ürününün başarısı, yaratıcılarının kullanıcılarına zarar vermeden önce bu sorunları ne kadar iyi çözebildiğine bağlıdır. Ve JavaScript, tüm programlama dilleri arasında, ortalama hata işleme tasarımıyla ünlüdür.
Bir JavaScript uygulaması oluşturuyorsanız, bir noktada veri türleriyle uğraşma olasılığınız çok yüksektir. Değilse, tanımsızı bir boş veya üçlü eşittir operatörü ( ===
) ile bir çift eşittir operatörü ( ==
) ile değiştirebilirsiniz.
Hata yapmak sadece insana mahsustur. Bu nedenle, JavaScript'teki hataları işleme hakkında bilmeniz gereken her şeyi size göstereceğiz.
Bu makale, JavaScript'teki temel hatalar konusunda size rehberlik edecek ve karşılaşabileceğiniz çeşitli hataları açıklayacaktır. Daha sonra bu hataları nasıl belirleyip düzelteceğinizi öğreneceksiniz. Ayrıca üretim ortamlarında hataları etkin bir şekilde ele almak için birkaç ipucu vardır.
Lafı fazla uzatmadan başlayalım!
JavaScript Hataları Nelerdir?
Programlamadaki hatalar, bir programın normal şekilde çalışmasına izin vermeyen durumlara atıfta bulunur. Bir program, mevcut olmayan bir dosyayı açmaya çalışırken veya ağ bağlantısı yokken web tabanlı bir API uç noktasına ulaşmaya çalışırken olduğu gibi, eldeki işi nasıl yapacağını bilmediğinde ortaya çıkabilir.
Bu durumlar programı nasıl ilerleyeceğini bilmediğini belirterek kullanıcıya hata atmaya zorlar. Program hata hakkında mümkün olduğu kadar çok bilgi toplar ve daha sonra ilerleyemeyeceğini bildirir.
Akıllı programcılar, kullanıcının “404” gibi teknik bir hata mesajını bağımsız olarak bulması gerekmemesi için bu senaryoları tahmin etmeye ve kapsamaya çalışır. Bunun yerine çok daha anlaşılır bir mesaj gösteriyorlar: "Sayfa bulunamadı."
JavaScript'teki hatalar, bir programlama hatası oluştuğunda gösterilen nesnelerdir. Bu nesneler, hatanın türü, hataya neden olan ifade ve hata oluştuğunda yığın izlemesi hakkında geniş bilgi içerir. JavaScript ayrıca, programcıların sorunları ayıklarken ekstra bilgi sağlamak için özel hatalar oluşturmasına da olanak tanır.
Bir Hatanın Özellikleri
Artık bir JavaScript hatasının tanımı açık olduğuna göre, ayrıntılara dalmanın zamanı geldi.
JavaScript'teki hatalar, hatanın nedenini ve etkilerini anlamaya yardımcı olan belirli standart ve özel özellikler taşır. Varsayılan olarak, JavaScript'teki hatalar üç özellik içerir:
- mesaj : Hata mesajını taşıyan bir dize değeri
- name : Oluşan hatanın türü (Buna bir sonraki bölümde ayrıntılı olarak değineceğiz)
- stack : Hata oluştuğunda yürütülen kodun yığın izi.
Ek olarak, hatalar, hatayı daha iyi açıklamak için columnNumber, lineNumber, fileName vb. özellikleri de taşıyabilir. Ancak, bu özellikler standart değildir ve JavaScript uygulamanızdan oluşturulan her hata nesnesinde bulunabilir veya bulunmayabilir.
Yığın İzlemeyi Anlama
Yığın izleme, istisna veya uyarı gibi bir olay meydana geldiğinde bir programın içinde bulunduğu yöntem çağrılarının listesidir. Bir istisnanın eşlik ettiği örnek bir yığın izlemesi şöyle görünür:

Gördüğünüz gibi, hata adını ve mesajını yazdırarak başlar, ardından çağrılan yöntemlerin bir listesi gelir. Her yöntem çağrısı, kaynak kodunun konumunu ve çağrıldığı satırı belirtir. Bu verileri kod tabanınızda gezinmek ve hangi kod parçasının hataya neden olduğunu belirlemek için kullanabilirsiniz.
Bu yöntem listesi yığılmış bir şekilde düzenlenmiştir. İstisnanızın ilk olarak nereye atıldığını ve yığınlanmış yöntem çağrıları aracılığıyla nasıl yayıldığını gösterir. İstisna için bir yakalama uygulamak, yığın boyunca yayılmasına ve programınızın çökmesine izin vermez. Ancak, bazı senaryolarda kasıtlı olarak programı çökertmek için önemli hataları yakalanmadan bırakmak isteyebilirsiniz.
Hatalar ve İstisnalar
Çoğu insan genellikle hataları ve istisnaları aynı şey olarak görür. Bununla birlikte, aralarında küçük ama temel bir farka dikkat etmek önemlidir.
Bunu daha iyi anlamak için hızlı bir örnek verelim. JavaScript'te bir hatayı şu şekilde tanımlayabilirsiniz:
const wrongTypeError = TypeError("Wrong type found, expected character")
Ve wrongTypeError
nesnesi bu şekilde bir istisna haline gelir:
throw wrongTypeError
Bununla birlikte, çoğu insan, onları fırlatırken hata nesnelerini tanımlayan stenografi biçimini kullanma eğilimindedir:
throw TypeError("Wrong type found, expected character")
Bu standart bir uygulamadır. Ancak, geliştiricilerin istisnaları ve hataları karıştırma eğiliminde olmasının nedenlerinden biri de budur. Bu nedenle, işinizi hızlı bir şekilde halletmek için stenografi kullansanız bile temelleri bilmek çok önemlidir.
JavaScript'teki Hata Türleri
JavaScript'te önceden tanımlanmış bir dizi hata türü vardır. Programcı uygulamadaki hataları açıkça işlemediğinde, JavaScript çalışma zamanı tarafından otomatik olarak seçilir ve tanımlanırlar.
Bu bölüm, JavaScript'teki en yaygın hata türlerinden bazılarında size yol gösterecek ve bunların ne zaman ve neden oluştuğunu anlayacaktır.
AralıkHatası
Bir değişken, yasal değerler aralığının dışında bir değere ayarlandığında bir RangeError atılır. Genellikle bir fonksiyona argüman olarak bir değer iletildiğinde ortaya çıkar ve verilen değer fonksiyonun parametrelerinin aralığında yer almaz. Bağımsız değişkenlerin doğru değeri iletmesi için olası değer aralığını bilmeniz gerektiğinden, yetersiz belgelenmiş üçüncü taraf kitaplıkları kullanırken bazen düzeltmek zor olabilir.
RangeError'ın meydana geldiği yaygın senaryolardan bazıları şunlardır:
- Array yapıcısı aracılığıyla bir dizi geçersiz uzunluk oluşturmaya çalışmak.
-
toExponential()
,toPrecision()
,toFixed()
vb. gibi sayısal yöntemlere hatalı değerler iletmek. -
normalize()
gibi dize işlevlerine geçersiz değerler iletmek.
Referans Hatası
Bir ReferenceError, kodunuzdaki bir değişkenin referansında bir sorun olduğunda ortaya çıkar. Değişkeni kullanmadan önce bir değer tanımlamayı unutmuş olabilirsiniz veya kodunuzda erişilemeyen bir değişken kullanmaya çalışıyor olabilirsiniz. Her durumda, yığın izinden geçmek, hatalı olan değişken referansını bulmak ve düzeltmek için yeterli bilgi sağlar.
ReferenceErrors'ın ortaya çıkmasının yaygın nedenlerinden bazıları şunlardır:
- Değişken adında yazım hatası yapmak.
- Blok kapsamlı değişkenlere kapsamlarının dışında erişmeye çalışmak.
- Yüklenmeden önce harici bir kitaplıktan (jQuery'den $ gibi) genel bir değişkene başvurma.
Sözdizimi hatası
Bu hatalar, kodun sözdiziminde bir hata olduğunu gösterdikleri için düzeltilmesi en basit olanlardan biridir. JavaScript, derlenmek yerine yorumlanan bir betik dili olduğundan, uygulama hatayı içeren betiği çalıştırdığında bunlar atılır. Derlenmiş diller söz konusu olduğunda, bu tür hatalar derleme sırasında belirlenir. Bu nedenle, bunlar düzeltilene kadar uygulama ikili dosyaları oluşturulmaz.
SyntaxErrors'ın oluşmasının yaygın nedenlerinden bazıları şunlardır:
- Ters virgül eksik
- Kapanış parantezleri eksik
- Kıvrımlı parantezlerin veya diğer karakterlerin yanlış hizalanması
Bu tür hataları tarayıcıya ulaşmadan önce sizin için belirlemek için IDE'nizde bir linting aracı kullanmak iyi bir uygulamadır.
TipHata
TypeError, JavaScript uygulamalarında en yaygın hatalardan biridir. Bu hata, bir değerin belirli bir beklenen türde olmadığı ortaya çıktığında oluşturulur. Meydana geldiği yaygın durumlardan bazıları şunlardır:
- Yöntem olmayan nesneleri çağırma.
- Boş veya tanımsız nesnelerin özelliklerine erişmeye çalışmak
- Bir dizeyi sayı olarak işlemek veya tam tersi
TypeError'ın oluşabileceği çok daha fazla olasılık vardır. Bazı ünlü örneklere daha sonra bakacağız ve bunları nasıl düzelteceğimizi öğreneceğiz.
İç hata
InternalError türü, JavaScript çalışma zamanı motorunda bir istisna oluştuğunda kullanılır. Kodunuzla ilgili bir sorunu gösterebilir veya göstermeyebilir.
Çoğu zaman, InternalError yalnızca iki senaryoda ortaya çıkar:
- JavaScript çalışma zamanındaki bir yama veya güncelleme, istisnalar oluşturan bir hata taşıdığında (bu çok nadiren olur)
- Kodunuz JavaScript motoru için çok büyük varlıklar içerdiğinde (örneğin, çok fazla anahtar durumu, çok büyük dizi başlatıcılar, çok fazla özyineleme)
Bu hatayı çözmek için en uygun yaklaşım, JavaScript motorundaki ani iş yükü artışını ortadan kaldırmak için, mümkünse, hata mesajı aracılığıyla nedeni belirlemek ve uygulama mantığınızı yeniden yapılandırmaktır.
URIE hatası
URIError, decodeURIComponent
gibi genel bir URI işleme işlevi yasa dışı olarak kullanıldığında oluşur. Genellikle yöntem çağrısına iletilen parametrenin URI standartlarına uymadığını ve bu nedenle yöntem tarafından düzgün bir şekilde ayrıştırılmadığını gösterir.
Yalnızca malformasyon argümanlarını incelemeniz gerektiğinden, bu hataları teşhis etmek genellikle kolaydır.
Değerlendirme Hatası
Bir eval()
işlev çağrısında bir hata oluştuğunda bir EvalError oluşur. eval()
işlevi, dizelerde saklanan JavaScript kodunu yürütmek için kullanılır. Ancak, güvenlik sorunları nedeniyle eval()
işlevinin kullanılması kesinlikle önerilmediğinden ve mevcut ECMAScript belirtimleri artık EvalError
sınıfını atmadığından, bu hata türü yalnızca eski JavaScript koduyla geriye dönük uyumluluğu korumak için mevcuttur.
JavaScript'in daha eski bir sürümü üzerinde çalışıyorsanız, bu hatayla karşılaşabilirsiniz. Her durumda, istisnalar için eval()
işlev çağrısında yürütülen kodu araştırmak en iyisidir.
Özel Hata Türleri Oluşturma
JavaScript, çoğu senaryoyu kapsayacak şekilde yeterli bir hata türü sınıfı listesi sunarken, liste gereksinimlerinizi karşılamıyorsa her zaman yeni bir hata türü oluşturabilirsiniz. Bu esnekliğin temeli, JavaScript'in, throw
komutuyla kelimenin tam anlamıyla herhangi bir şeyi atmanıza izin vermesi gerçeğinde yatmaktadır.
Bu nedenle, teknik olarak, bu ifadeler tamamen yasaldır:
throw 8 throw "An error occurred"
Ancak, ilkel bir veri türü atmak, türü, adı veya beraberindeki yığın izlemesi gibi hata hakkında ayrıntılar sağlamaz. Bunu düzeltmek ve hata işleme sürecini standart hale getirmek için Error
sınıfı sağlanmıştır. İstisnalar atılırken ilkel veri türlerinin kullanılması da önerilmez.
Özel hata sınıfınızı oluşturmak için Error
sınıfını genişletebilirsiniz. İşte bunu nasıl yapabileceğinize dair temel bir örnek:
class ValidationError extends Error { constructor(message) { super(message); this.name = "ValidationError"; } }
Ve aşağıdaki şekilde kullanabilirsiniz:
throw ValidationError("Property not found: name")
Ardından instanceof
anahtar sözcüğünü kullanarak tanımlayabilirsiniz:
try { validateForm() // code that throws a ValidationError } catch (e) { if (e instanceof ValidationError) // do something else // do something else }
JavaScript'te En Yaygın 10 Hata
Artık yaygın hata türlerini ve kendi özel hatalarınızı nasıl oluşturacağınızı anladığınıza göre, JavaScript kodu yazarken karşılaşacağınız en yaygın hatalardan bazılarına bakmanın zamanı geldi.
1. Yakalanmayan Menzil Hatası
Bu hata, Google Chrome'da birkaç farklı senaryoda ortaya çıkar. İlk olarak, özyinelemeli bir işlev çağırırsanız ve sonlandırılmazsa bu gerçekleşebilir. Bunu Chrome Developer Console'da kendiniz kontrol edebilirsiniz:

Bu yüzden böyle bir hatayı çözmek için özyinelemeli işlevinizin sınır durumlarını doğru tanımladığınızdan emin olun. Bu hatanın oluşmasının bir başka nedeni de, bir işlevin parametre aralığının dışında bir değer iletmiş olmanızdır. İşte bir örnek:

Hata mesajı genellikle kodunuzda neyin yanlış olduğunu gösterir. Değişiklikleri yaptığınızda sorun çözülecektir.

2. Yakalanmayan TypeError: Özellik ayarlanamıyor
Bu hata, tanımsız bir başvuruda bir özellik ayarladığınızda oluşur. Sorunu bu kodla yeniden oluşturabilirsiniz:
var list list.count = 0
İşte alacağınız çıktı:

Bu hatayı düzeltmek için, özelliklerine erişmeden önce referansı bir değerle başlatın. Düzeltildiğinde nasıl göründüğü aşağıda açıklanmıştır:

3. Yakalanmayan TypeError: Özellik okunamıyor
Bu, JavaScript'te en sık meydana gelen hatalardan biridir. Bu hata, tanımsız bir nesnede bir özelliği okumaya veya bir işlevi çağırmaya çalıştığınızda oluşur. Aşağıdaki kodu bir Chrome Geliştirici konsolunda çalıştırarak çok kolay bir şekilde çoğaltabilirsiniz:
var func func.call()
İşte çıktı:

Tanımsız bir nesne, bu hatanın olası birçok nedeninden biridir. Bu sorunun bir diğer önemli nedeni, kullanıcı arayüzü oluşturulurken durumun yanlış başlatılması olabilir. İşte bir React uygulamasından gerçek dünyadan bir örnek:
import React, { useState, useEffect } from "react"; const CardsList = () => { const [state, setState] = useState(); useEffect(() => { setTimeout(() => setState({ items: ["Card 1", "Card 2"] }), 2000); }, []); return ( <> {state.items.map((item) => ( <li key={item}>{item}</li> ))} </> ); }; export default CardsList;
Uygulama, boş bir durum kapsayıcısıyla başlar ve 2 saniyelik bir gecikmeden sonra bazı öğelerle birlikte sağlanır. Gecikme, bir şebeke aramasını taklit etmek için yerleştirilir. Ağınız süper hızlı olsa bile, bileşenin en az bir kez oluşturulacağından dolayı yine de küçük bir gecikmeyle karşılaşacaksınız. Bu uygulamayı çalıştırmayı denerseniz, aşağıdaki hatayı alırsınız:

Bunun nedeni, oluşturma sırasında durum kapsayıcısının tanımsız olmasıdır; bu nedenle, üzerinde hiçbir özellik items
yoktur. Bu hatayı düzeltmek kolaydır. Durum kapsayıcısına bir başlangıç varsayılan değeri sağlamanız yeterlidir.
// ... const [state, setState] = useState({items: []}); // ...
Şimdi, ayarlanan gecikmeden sonra uygulamanız benzer bir çıktı gösterecektir:

Kodunuzdaki tam düzeltme farklı olabilir, ancak buradaki öz, değişkenlerinizi kullanmadan önce her zaman düzgün bir şekilde başlatmaktır.
4. TypeError: 'tanımsız' bir nesne değil
Bu hata, Safari'de tanımsız bir nesnenin özelliklerine erişmeye veya bir yöntemi çağırmaya çalıştığınızda oluşur. Hatayı kendiniz yeniden oluşturmak için aynı kodu yukarıdan çalıştırabilirsiniz.

Bu hatanın çözümü de aynıdır — değişkenlerinizi doğru bir şekilde başlattığınızdan ve bir özelliğe veya yönteme erişildiğinde tanımsız olmadıklarından emin olun.
5. TypeError: null bir nesne değil
Bu, yine, önceki hataya benzer. Safari'de oluşur ve iki hata arasındaki tek fark, özelliği veya yöntemine erişilen nesne undefined
yerine null
olduğunda bunun atılmasıdır. Aşağıdaki kod parçasını çalıştırarak bunu çoğaltabilirsiniz:
var func = null func.call()
İşte alacağınız çıktı:

null
, açıkça bir değişkene ayarlanmış ve JavaScript tarafından otomatik olarak atanmamış bir değer olduğundan. Bu hata, yalnızca kendiniz null
olarak ayarladığınız bir değişkene erişmeye çalışıyorsanız oluşabilir. Bu yüzden kodunuzu tekrar gözden geçirmeniz ve yazdığınız mantığın doğru olup olmadığını kontrol etmeniz gerekiyor.
6. TypeError: 'uzunluk' özelliği okunamıyor
Bu hata, null
veya undefined
bir nesnenin uzunluğunu okumaya çalıştığınızda Chrome'da oluşur. Bu sorunun nedeni önceki sorunlara benzer, ancak listeleri işlerken oldukça sık ortaya çıkıyor; bu nedenle özel bir sözü hak ediyor. Sorunu şu şekilde yeniden oluşturabilirsiniz:

Ancak, Chrome'un daha yeni sürümlerinde, bu hata Uncaught TypeError: Cannot read properties of undefined
olarak bildirilir. Şimdi böyle görünüyor:

Düzeltme, yine, uzunluğuna erişmeye çalıştığınız nesnenin var olduğundan ve null
olarak ayarlanmadığından emin olmaktır.
7. TypeError: 'tanımsız' bir işlev değil
Bu hata, betiğinizde olmayan bir yöntemi çağırmaya çalıştığınızda veya var olan ancak çağrı bağlamında başvurulamadığı zaman oluşur. Bu hata genellikle Google Chrome'da oluşur ve hatayı veren kod satırını kontrol ederek çözebilirsiniz. Bir yazım hatası bulursanız düzeltin ve sorununuzu çözüp çözmediğini kontrol edin.
Kodunuzda kendi kendine başvuran this
anahtar sözcüğünü kullandıysanız, bu, bağlamınıza uygun şekilde bağlı değilse this
hata ortaya çıkabilir. Aşağıdaki kodu göz önünde bulundurun:
function showAlert() { alert("message here") } document.addEventListener("click", () => { this.showAlert(); })
Yukarıdaki kodu çalıştırırsanız, tartıştığımız hatayı verecektir. Bunun nedeni, olay dinleyicisi document
bağlamında yürütülürken geçirilen anonim işlevdir.
Buna karşılık, showAlert
işlevi, window
bağlamında tanımlanır.
Bunu çözmek için, fonksiyona uygun referansı bind()
yöntemiyle bağlayarak iletmelisiniz:
document.addEventListener("click", this.showAlert.bind(this))
8. ReferenceError: olay tanımlı değil
Bu hata, çağrı kapsamında tanımlanmayan bir başvuruya erişmeye çalıştığınızda oluşur. Bu genellikle olayları işlerken olur, çünkü bunlar genellikle size geri arama işlevinde event
adlı bir referans sağlar. Bu hata, olay bağımsız değişkenini işlevinizin parametrelerinde tanımlamayı unutursanız veya yanlış yazarsanız oluşabilir.
Bu hata Internet Explorer veya Google Chrome'da oluşmayabilir (IE genel bir olay değişkeni sunduğundan ve Chrome olay değişkenini işleyiciye otomatik olarak eklediğinden), ancak Firefox'ta oluşabilir. Bu nedenle, bu tür küçük hatalara dikkat etmeniz önerilir.

9. TypeError: Sabit değişkene atama
Bu, dikkatsizlikten kaynaklanan bir hatadır. Sabit bir değişkene yeni bir değer atamaya çalışırsanız, şöyle bir sonuçla karşılaşırsınız:

Şu anda düzeltmesi kolay gibi görünse de, bu tür yüzlerce değişken bildirimi ve bunlardan birinin yanlışlıkla let
yerine const
olarak tanımlandığını hayal edin! PHP gibi diğer betik dillerinden farklı olarak, JavaScript'te sabitleri ve değişkenleri bildirme stili arasında çok az fark vardır. Bu nedenle, bu hatayla karşılaştığınızda öncelikle beyanlarınızı kontrol etmeniz önerilir. Bahsedilen referansın bir sabit olduğunu unutursanız ve onu bir değişken olarak kullanırsanız, bu hatayla da karşılaşabilirsiniz. Bu, uygulamanızın mantığındaki dikkatsizliği veya kusuru gösterir. Bu sorunu düzeltmeye çalışırken bunu kontrol ettiğinizden emin olun.
10. (bilinmeyen): Komut dosyası hatası
Bir üçüncü taraf komut dosyası tarayıcınıza bir hata gönderdiğinde bir komut dosyası hatası oluşur. Üçüncü taraf komut dosyası uygulamanızdan farklı bir etki alanına ait olduğundan bu hatayı (bilinmeyen) izler. Tarayıcı, üçüncü taraf komut dosyasından hassas bilgilerin sızmasını önlemek için diğer ayrıntıları gizler.
Tüm detayları bilmeden bu hatayı çözemezsiniz. Hata hakkında daha fazla bilgi almak için şunları yapabilirsiniz:
- Script etiketine
crossorigin
niteliğini ekleyin. - Komut dosyasını barındıran sunucuda doğru
Access-Control-Allow-Origin
başlığını ayarlayın. - [İsteğe bağlı] Komut dosyasını barındıran sunucuya erişiminiz yoksa, isteğinizi sunucuya iletmek ve doğru başlıklarla istemciye geri göndermek için bir proxy kullanmayı düşünebilirsiniz.
Hatanın ayrıntılarına eriştikten sonra, muhtemelen üçüncü taraf kitaplığı veya ağ ile ilgili olacak sorunu çözmek için ayarlayabilirsiniz.
JavaScript'te Hatalar Nasıl Belirlenir ve Önlenir
Yukarıda tartışılan hatalar JavaScript'te en yaygın ve sık görülen hatalar olsa da, karşılaşacağınız birkaç örneğe güvenmek asla yeterli olamaz. Bir JavaScript uygulamasını geliştirirken herhangi bir türdeki hatayı nasıl tespit edip önleyeceğinizi anlamak çok önemlidir. JavaScript'teki hataları nasıl ele alacağınız aşağıda açıklanmıştır.
Manuel Olarak Atma ve Hataları Yakalama
Manuel olarak veya çalışma zamanı tarafından atılan hataları ele almanın en temel yolu onları yakalamaktır. Diğer dillerin çoğu gibi, JavaScript de hataları işlemek için bir dizi anahtar kelime sunar. JavaScript uygulamanızdaki hataları işlemeye başlamadan önce her birini derinlemesine bilmek önemlidir.
atmak
Kümenin ilk ve en temel anahtar sözcüğü throw
. Açıkça görüldüğü gibi, throw anahtar sözcüğü, JavaScript çalışma zamanında manuel olarak istisnalar oluşturmak için hataları atmak için kullanılır. Bunu daha önce parçada tartışmıştık ve işte bu anahtar kelimenin öneminin özü:
- Sayılar, dizeler ve
Error
nesneleri dahil her şeyithrow
. - Ancak, dizeler ve sayılar gibi ilkel veri türlerinin hatalarla ilgili hata ayıklama bilgisi taşımadığından atılması önerilmez.
- Örnek:
throw TypeError("Please provide a string")
denemek
try
anahtar sözcüğü, bir kod bloğunun bir istisna oluşturabileceğini belirtmek için kullanılır. Sözdizimi:
try { // error-prone code here }
Hataları etkili bir şekilde ele almak için bir catch
bloğunun her zaman try
bloğunu takip etmesi gerektiğini unutmamak önemlidir.
tutmak
Catch anahtar sözcüğü, bir catch
bloğu oluşturmak için kullanılır. Bu kod bloğu, takip eden try
bloğunun yakaladığı hataların işlenmesinden sorumludur. İşte sözdizimi:
catch (exception) { // code to handle the exception here }
Ve bu, try
ve catch
bloklarını birlikte nasıl uygularsınız:
try { // business logic code } catch (exception) { // error handling code }
C++ veya Java'dan farklı olarak, JavaScript'te bir try
bloğuna birden çok catch
bloğu ekleyemezsiniz. Bu, bunu yapamayacağınız anlamına gelir:
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } } catch (exception) { if (exception instanceof RangeError) { // do something } }
Bunun yerine, olası tüm hata durumlarını işlemek için tek bir yakalama bloğunun içinde bir if...else
ifadesi veya bir switch case ifadesi kullanabilirsiniz. Şuna benzer:
try { // business logic code } catch (exception) { if (exception instanceof TypeError) { // do something } else if (exception instanceof RangeError) { // do something else } }
Sonunda
finally
anahtar sözcüğü, bir hata işlendikten sonra çalıştırılan bir kod bloğunu tanımlamak için kullanılır. Bu blok, try ve catch bloklarından sonra yürütülür.
Ayrıca, son blok, diğer iki bloğun sonucundan bağımsız olarak yürütülecektir. Bu, catch bloğu hatayı tamamen işleyemese veya catch bloğunda bir hata atılsa bile, yorumlayıcının program çökmeden önce son bloktaki kodu çalıştıracağı anlamına gelir.
Geçerli sayılması için JavaScript'teki try bloğunun ardından bir catch ya da nihayet bloğunun gelmesi gerekir. Bunların hiçbiri olmazsa, yorumlayıcı bir SyntaxError oluşturacaktır. Bu nedenle, hataları işlerken deneme bloklarınızı en azından bunlardan biri ile takip ettiğinizden emin olun.
Onerror() Yöntemiyle Hataları Global Olarak İşleyin
onerror()
yöntemi, kendilerinde meydana gelebilecek herhangi bir hatayı işlemek için tüm HTML öğelerinde kullanılabilir. Örneğin, bir img
etiketi URL'si belirtilen resmi bulamazsa, kullanıcının hatayı işlemesine izin vermek için onerror yöntemini çalıştırır.
Tipik olarak, img
etiketinin geri dönmesi için hata çağrısında başka bir resim URL'si sağlarsınız. Bunu JavaScript aracılığıyla şu şekilde yapabilirsiniz:
const image = document.querySelector("img") image.onerror = (event) => { console.log("Error occurred: " + event) }
Ancak, uygulamanız için genel bir hata işleme mekanizması oluşturmak için bu özelliği kullanabilirsiniz. Bunu şu şekilde yapabilirsiniz:
window.onerror = (event) => { console.log("Error occurred: " + event) }
Bu olay işleyici ile, kodunuzda bulunan birden çok try...catch
bloğundan kurtulabilir ve uygulamanızın hata işlemesini olay işlemeye benzer şekilde merkezileştirebilirsiniz. SOLID tasarım ilkelerinden Tek Sorumluluk İlkesini korumak için pencereye birden çok hata işleyici ekleyebilirsiniz. Tercüman, uygun olana ulaşana kadar tüm işleyiciler arasında geçiş yapacaktır.
Geri Aramalar Yoluyla Hataları İletin
Basit ve doğrusal işlevler, hata işlemenin basit kalmasına izin verirken, geri aramalar meseleyi karmaşıklaştırabilir.
Aşağıdaki kod parçasını göz önünde bulundurun:
Size rekabet avantajı sağlayan bir barındırma çözümüne mi ihtiyacınız var? Kinsta sizi inanılmaz hız, son teknoloji güvenlik ve otomatik ölçeklendirme ile donattı. Planlarımıza göz atın
const calculateCube = (number, callback) => { setTimeout(() => { const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) calculateCube(4, callback)
Yukarıdaki işlev, bir işlevin işlemleri işlemesinin biraz zaman aldığı ve sonucu daha sonra bir geri arama yardımıyla döndürdüğü zaman uyumsuz bir koşulu gösterir.
İşlev çağrısında 4 yerine bir dize girmeye çalışırsanız, sonuç olarak NaN
alırsınız.
Bunun düzgün bir şekilde ele alınması gerekiyor. İşte nasıl:
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") throw new Error("Numeric argument is expected") const cube = number * number * number callback(cube) }, 1000) } const callback = result => console.log(result) try { calculateCube(4, callback) } catch (e) { console.log(e) }
Bu sorunu ideal olarak çözmelidir. Ancak, işlev çağrısına bir dize iletmeyi denerseniz, şunu alırsınız:

İşlevi çağırırken bir try-catch bloğu uygulamış olsanız bile, yine de hatanın yakalanmadığını söylüyor. Hata, zaman aşımı gecikmesi nedeniyle yakalama bloğu yürütüldükten sonra atılır.
Bu, beklenmedik gecikmelerin ortaya çıktığı ağ aramalarında hızlı bir şekilde ortaya çıkabilir. Uygulamanızı geliştirirken bu tür durumları kapsamanız gerekir.
Geri aramalarda hataları düzgün bir şekilde nasıl halledebileceğiniz aşağıda açıklanmıştır:
const calculateCube = (number, callback) => { setTimeout(() => { if (typeof number !== "number") { callback(new TypeError("Numeric argument is expected")) return } const cube = number * number * number callback(null, cube) }, 2000) } const callback = (error, result) => { if (error !== null) { console.log(error) return } console.log(result) } try { calculateCube('hey', callback) } catch (e) { console.log(e) }
Şimdi, konsoldaki çıktı şöyle olacaktır:

Bu, hatanın uygun şekilde işlendiğini gösterir.
Sözlerdeki Hataları İşleyin
Çoğu insan, asenkron etkinlikleri işlemek için vaatleri tercih etme eğilimindedir. Sözlerin başka bir avantajı daha vardır - reddedilen bir söz, senaryonuzu sonlandırmaz. Ancak, sözlerdeki hataları işlemek için yine de bir yakalama bloğu uygulamanız gerekir. Bunu daha iyi anlamak için, Promises'ı kullanarak hesapCube calculateCube()
işlevini yeniden yazalım:
const delay = ms => new Promise(res => setTimeout(res, ms)); const calculateCube = async (number) => { if (typeof number !== "number") throw Error("Numeric argument is expected") await delay(5000) const cube = number * number * number return cube } try { calculateCube(4).then(r => console.log(r)) } catch (e) { console.log(e) }
Önceki kodun zaman aşımı, anlaşılması için delay
işlevinde izole edilmiştir. 4 yerine bir dize girmeye çalışırsanız, alacağınız çıktı şuna benzer olacaktır:

Yine, bu, diğer her şeyin yürütmeyi tamamladıktan sonra hatayı atma Promise
kaynaklanmaktadır. Bu sorunun çözümü basittir. Söz zincirine aşağıdaki gibi bir catch()
çağrısı eklemeniz yeterlidir:
calculateCube("hey") .then(r => console.log(r)) .catch(e => console.log(e))
Şimdi çıktı şöyle olacaktır:

Söz vererek hataların üstesinden gelmenin ne kadar kolay olduğunu gözlemleyebilirsiniz. Ek olarak, bir finally()
bloğunu zincirleyebilir ve hata işleme tamamlandıktan sonra çalışacak kod ekleme sözü çağrısını yapabilirsiniz.
Alternatif olarak, geleneksel try-catch-finally tekniğini kullanarak vaatlerdeki hataları da halledebilirsiniz. Bu durumda söz aramanızın nasıl görüneceği aşağıda açıklanmıştır:
try { let result = await calculateCube("hey") console.log(result) } catch (e) { console.log(e) } finally { console.log('Finally executed") }
Ancak bu, yalnızca eşzamansız bir işlev içinde çalışır. Bu nedenle sözlerdeki hataları ele almanın en çok tercih edilen yolu zincirleme catch
ve finally
olarak söz çağrısına gitmektir.
throw/catch vs onerror() vs Callbacks vs Promises: Hangisi En İyisi?
Emrinizde olan dört yöntem ile, herhangi bir kullanım durumunda en uygun olanı nasıl seçeceğinizi bilmelisiniz. Kendiniz için şu şekilde karar verebilirsiniz:
atmak/yakalamak
Çoğu zaman bu yöntemi kullanacaksınız. Catch bloğunuzdaki tüm olası hatalar için koşulları uyguladığınızdan emin olun ve try bloğundan sonra bazı bellek temizleme rutinlerini çalıştırmanız gerekiyorsa bir nihayet bloğu eklemeyi unutmayın.
Ancak, çok fazla dene/yakala bloğu, kodunuzun bakımını zorlaştırabilir. Kendinizi böyle bir durumda bulursanız, genel işleyici veya söz verme yöntemi aracılığıyla hataları ele almak isteyebilirsiniz.
Eşzamansız try/catch blokları ile sözde catch()
arasında karar verirken, kodunuzu doğrusal ve hata ayıklamayı kolaylaştıracaklarından, zaman uyumsuz try/catch bloklarını kullanmanız önerilir.
hata()
Uygulamanızın birçok hatayı işlemesi gerektiğini ve bunların kod temeli boyunca iyi dağılmış olabileceğini bildiğinizde onerror()
yöntemini kullanmak en iyisidir. onerror
yöntemi, hataları uygulamanız tarafından işlenen başka bir olaymış gibi işlemenizi sağlar. Birden çok hata işleyici tanımlayabilir ve bunları ilk işleme sırasında uygulamanızın penceresine ekleyebilirsiniz.
Ancak, onerror()
yönteminin daha az hata kapsamına sahip daha küçük projelerde kurulmasının gereksiz yere zorlayıcı olabileceğini de unutmamalısınız. Uygulamanızın çok fazla hata atmayacağından eminseniz, geleneksel fırlat/yakala yöntemi sizin için en iyi sonucu verecektir.
Geri aramalar ve vaatler
Geri aramalarda ve vaatlerde hata işleme, kod tasarımı ve yapısı nedeniyle farklılık gösterir. Ancak, kodunuzu yazmadan önce bu ikisi arasında seçim yaparsanız, vaatlerle gitmek en iyisi olacaktır.
Bunun nedeni, vaatlerin, hataları kolayca işlemek için bir catch()
ve bir finally()
bloğunu zincirlemek için yerleşik bir yapıya sahip olmasıdır. This method is easier and cleaner than defining additional arguments/reusing existing arguments to handle errors.
Keep Track of Changes With Git Repositories
Many errors often arise due to manual mistakes in the codebase. While developing or debugging your code, you might end up making unnecessary changes that may cause new errors to appear in your codebase. Automated testing is a great way to keep your code in check after every change. However, it can only tell you if something's wrong. If you don't take frequent backups of your code, you'll end up wasting time trying to fix a function or a script that was working just fine before.
This is where git plays its role. With a proper commit strategy, you can use your git history as a backup system to view your code as it evolved through the development. You can easily browse through your older commits and find out the version of the function working fine before but throwing errors after an unrelated change.
You can then restore the old code or compare the two versions to determine what went wrong. Modern web development tools like GitHub Desktop or GitKraken help you to visualize these changes side by side and figure out the mistakes quickly.
A habit that can help you make fewer errors is running code reviews whenever you make a significant change to your code. If you're working in a team, you can create a pull request and have a team member review it thoroughly. This will help you use a second pair of eyes to spot out any errors that might have slipped by you.
Best Practices for Handling Errors in JavaScript
The above-mentioned methods are adequate to help you design a robust error handling approach for your next JavaScript application. However, it would be best to keep a few things in mind while implementing them to get the best out of your error-proofing. Here are some tips to help you.
1. Use Custom Errors When Handling Operational Exceptions
We introduced custom errors early in this guide to give you an idea of how to customize the error handling to your application's unique case. It's advisable to use custom errors wherever possible instead of the generic Error
class as it provides more contextual information to the calling environment about the error.
On top of that, custom errors allow you to moderate how an error is displayed to the calling environment. This means that you can choose to hide specific details or display additional information about the error as and when you wish.
You can go so far as to format the error contents according to your needs. This gives you better control over how the error is interpreted and handled.
2. Do Not Swallow Any Exceptions
Even the most senior developers often make a rookie mistake — consuming exceptions levels deep down in their code.
You might come across situations where you have a piece of code that is optional to run. If it works, great; if it doesn't, you don't need to do anything about it.
In these cases, it's often tempting to put this code in a try block and attach an empty catch block to it. However, by doing this, you'll leave that piece of code open to causing any kind of error and getting away with it. This can become dangerous if you have a large codebase and many instances of such poor error management constructs.
The best way to handle exceptions is to determine a level on which all of them will be dealt and raise them until there. This level can be a controller (in an MVC architecture app) or a middleware (in a traditional server-oriented app).
This way, you'll get to know where you can find all the errors occurring in your app and choose how to resolve them, even if it means not doing anything about them.
3. Use a Centralized Strategy for Logs and Error Alerts
Logging an error is often an integral part of handling it. Those who fail to develop a centralized strategy for logging errors may miss out on valuable information about their app's usage.
An app's event logs can help you figure out crucial data about errors and help to debug them quickly. If you have proper alerting mechanisms set up in your app, you can know when an error occurs in your app before it reaches a large section of your user base.
It's advisable to use a pre-built logger or create one to suit your needs. You can configure this logger to handle errors based on their levels (warning, debug, info, etc.), and some loggers even go so far as to send logs to remote logging servers immediately. This way, you can watch how your application's logic performs with active users.
4. Notify Users About Errors Appropriately
Another good point to keep in mind while defining your error handling strategy is to keep the user in mind.
All errors that interfere with the normal functioning of your app must present a visible alert to the user to notify them that something went wrong so the user can try to work out a solution. If you know a quick fix for the error, such as retrying an operation or logging out and logging back in, make sure to mention it in the alert to help fix the user experience in real-time.
In the case of errors that don't cause any interference with the everyday user experience, you can consider suppressing the alert and logging the error to a remote server for resolving later.
5. Implement a Middleware (Node.js)
The Node.js environment supports middlewares to add functionalities to server applications. You can use this feature to create an error-handling middleware for your server.
The most significant benefit of using middleware is that all of your errors are handled centrally in one place. You can choose to enable/disable this setup for testing purposes easily.
Here's how you can create a basic middleware:
const logError = err => { console.log("ERROR: " + String(err)) } const errorLoggerMiddleware = (err, req, res, next) => { logError(err) next(err) } const returnErrorMiddleware = (err, req, res, next) => { res.status(err.statusCode || 500) .send(err.message) } module.exports = { logError, errorLoggerMiddleware, returnErrorMiddleware }
Daha sonra bu ara yazılımı uygulamanızda şu şekilde kullanabilirsiniz:
const { errorLoggerMiddleware, returnErrorMiddleware } = require('./errorMiddleware') app.use(errorLoggerMiddleware) app.use(returnErrorMiddleware)
Artık hataları uygun şekilde işlemek için ara katman yazılımı içinde özel mantık tanımlayabilirsiniz. Artık kod tabanınız boyunca bireysel hata işleme yapılarını uygulama konusunda endişelenmenize gerek yok.
6. Programcı Hatalarını (Node.js) işlemek için Uygulamanızı Yeniden Başlatın
Node.js uygulamaları programcı hatalarıyla karşılaştığında, mutlaka bir istisna oluşturmayabilir ve uygulamayı kapatmaya çalışmayabilir. Bu tür hatalar, yüksek CPU tüketimi, bellek şişmesi veya bellek sızıntıları gibi programcı hatalarından kaynaklanan sorunları içerebilir. Bunları ele almanın en iyi yolu, uygulamayı Node.js küme modu veya PM2 gibi benzersiz bir araç aracılığıyla kilitleyerek uygulamayı düzgün bir şekilde yeniden başlatmaktır. Bu, uygulamanın kullanıcı eylemi üzerine çökmemesini ve korkunç bir kullanıcı deneyimi sunmamasını sağlayabilir.
7. Yakalanmayan Tüm İstisnaları Yakalayın (Node.js)
Uygulamanızda oluşabilecek her olası hatayı ele aldığınızdan asla emin olamazsınız. Bu nedenle, uygulamanızdan yakalanmamış tüm istisnaları yakalamak için bir geri dönüş stratejisi uygulamak çok önemlidir.
Bunu şu şekilde yapabilirsiniz:
process.on('uncaughtException', error => { console.log("ERROR: " + String(error)) // other handling mechanisms })
Ayrıca oluşan hatanın standart bir istisna mı yoksa özel bir işlem hatası mı olduğunu belirleyebilirsiniz. Sonuca göre, beklenmeyen davranışlardan kaçınmak için süreçten çıkıp yeniden başlatabilirsiniz.
8. İşlenmeyen Tüm Söz Reddlerini Yakalayın (Node.js)
Tüm olası istisnaları asla karşılayamayacağınıza benzer şekilde, tüm olası vaat reddini ele alma konusunda yüksek bir şansınız var. Ancak, istisnalardan farklı olarak, söz verme retleri hata oluşturmaz.
Bu nedenle, reddedilen önemli bir söz bir uyarı olarak gözden kaçabilir ve uygulamanızı beklenmedik davranışlarla karşılaşma olasılığına açık bırakabilir. Bu nedenle, söz reddini işlemek için bir geri dönüş mekanizması uygulamak çok önemlidir.
Bunu şu şekilde yapabilirsiniz:
const promiseRejectionCallback = error => { console.log("PROMISE REJECTED: " + String(error)) } process.on('unhandledRejection', callback)
Özet
Diğer programlama dilleri gibi, JavaScript'te de hatalar oldukça sık ve doğaldır. Bazı durumlarda, kullanıcılarınıza doğru yanıtı belirtmek için kasıtlı olarak hatalar göndermeniz bile gerekebilir. Bu nedenle, anatomilerini ve türlerini anlamak çok önemlidir.
Ayrıca, uygulamanızı devre dışı bırakmaktan kaynaklanan hataları belirlemek ve önlemek için doğru araç ve tekniklerle donatılmış olmanız gerekir.
Çoğu durumda, her tür JavaScript uygulaması için hataları dikkatli yürütmeyle ele almak için sağlam bir strateji yeterlidir.
Hala çözemediğiniz başka JavaScript hataları var mı? JS hatalarını yapıcı bir şekilde ele almak için herhangi bir teknik var mı? Aşağıdaki yorumlarda bize bildirin!