JavaScript Özel Durum İşleme


82

JavaScript içinde atılan TÜM istisnaları yakalamak için en iyi teknik nedir?

Açıkçası, en iyi teknik try ... catch'i kullanmaktır. Ancak eşzamansız geri aramalar ve benzerleri söz konusu olduğunda bu biraz yanıltıcı olabilir.

IE ve Gecko tarayıcılarının window.onerror'u desteklediğini biliyorum, peki ya Opera ve Safari?

Burada, merkezi bir istisna işleme çözümüne sahip olmak istediğim bir dizi test durumu yer almaktadır:

// ErrorHandler-Test1
var test = null;
test.arg = 5;
// ErrorHandler-Test2
throw (new Error("Hello"));
// ErrorHandler-Test3
throw "Hello again";
// ErrorHandler-Test4
throw {
    myMessage: "stuff",
    customProperty: 5,
    anArray: [1, 2, 3]
};
// ErrorHandler-Test5
try {
    var test2 = null;
    test2.arg = 5;
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test6
try {
    throw (new Error("Goodbye"));
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test7
try {
    throw "Goodbye again";
} catch(e) {
    ErrorHandler.handleError(e);
}
// ErrorHandler-Test8
try {
    throw {
        myMessage: "stuff",
        customProperty: 5,
        anArray: [1, 2, 3]
    };
} catch(e) {
    ErrorHandler.handleError(e);
}

Aklınıza başka bir test durumu gelirse, lütfen bunlardan bahsedin. Bu durumların birçoğu bir ErrorHandler.handleError yönteminden bahsetmektedir. Bu sadece try ... catch kullanılırken önerilen bir kılavuzdur.


Cevabımdaki yorumları fark etmediğiniz açık olduğu için: bir soru olarak okunduğunda "soruda belirtilen" için bana olumsuz oy vermişsiniz: "peki ya Opera ve Safari?" Burada sorulan bir soruyu özellikle cevapladım. O NE LAN?
göz kapaksızlık

1
WebKit'te, window.onerroreksiklik 2003'ten beri bir sorundur , ancak sonunda çözülmüş gibi görünüyor . Tabii ki Opera inatçı kalacaktır.
josh3736

Bilginize window.onerror iyi çalışıyor - Firefox 7.0.1 - IE 8 - Chrome 16 - Opera 11.60
Vitaliy Kaplich

11
Bunun neden kapalı olduğundan emin değilim. Yeniden açılmasına oy verildi.
ripper234

1
Kabul edildi, bu yararlı bir sorudur. Aklıma gelen tek şey casperOne'ın bunun yerine bir tür tarayıcı savaşı tartışmasına dönüşeceğinden korkması?
Jordan Reiter

Yanıtlar:


23

Tüm olay işleyicilerinizi atamak için jQuery gibi bir kitaplık kullanıyorsanız window.onerror, jQuery olay işleyici kodunu ve bir hata işleme işleviyle ready işlevini bir arada kullanabilirsiniz (bkz. JavaScript Hata İzleme: Neden window.onerror Is Not Enough) ).

  • window.onerror: IE'deki tüm hataları (ve Firefox'taki çoğu hatayı) yakalar, ancak Safari ve Opera'da hiçbir şey yapmaz.
  • jQuery olay işleyicileri: tüm tarayıcılarda jQuery olay hatalarını yakalar.
  • jQuery ready işlevi: tüm tarayıcılarda başlatma hatalarını yakalar.

Çözüm sunmayan makaleyi daha önce okumuştum. JQuery kullanmıyorum ama ne ima ettiğin konusunda endişeliyim. JQuery'nin istisnalar yediğini mi söylüyorsunuz ?! Yoksa yalnızca bir günlük tutma işlevi mi sağlıyorlar (bu yalnızca ilk sorum yanıtlandıktan sonra işe yarar)?
harley. 333

jQuery, İstisnalar ile özel bir şey yapmaz. Ancak, tüm olaylarınızı eklemek için jQuery kullanıyorsanız, cevabımdaki ikinci bağlantıda açıklandığı gibi, try catch deyiminizi ve hata işleme kodunuzu eklemek için size tek bir yer sağlar.
Karl

2
Sağlanan bağlantı taşındı: blogs.cozi.com/tech/2008/04/…
natacado

1
Bu hala doğru mu? onerrorSafari + Chrome'da normal kullanım yaklaşımını denedim ve düzgün çalışıyor gibi görünüyor.
Juri

Neden "yeterli değil" sorusuna verdiğiniz bağlantı oldukça eski bir bilgi ve şu anda durum böyle değil.
vsync

21

WebKit (Safari, Chrome vb.) Artık desteklediği görülüyor onerror.

Orijinal gönderi: Bildiğim kadarıyla WebKit / Safari, onerroretkinliği desteklemiyor . Bu büyük bir utanç.


19
Hayır değil. Şu soruda soruldu: "peki ya Opera ve Safari?"
eyelidlessness

Olduğu gibi, soru gönderisinde sorulan bir soruyu özellikle cevapladım.
eyelidlessness

8
Sanırım "Opera ve Safari hakkında [window.onerror'u olmayan] ne [yapmalıyım]?"
nickf

10
@nickf, belki, ama eğer öyleyse çok kötü yazılmış ve benim yorumum en kötü ihtimalle anlaşılır ve en iyi ihtimalle de büyük olasılıkla. İnsanlar benim cevap aşağı oy vermek için özellikle soru göz önüne alındığında, oldukça kötü bir nedendir vermez devlet onu ve diğer okuyucular olumlu veya olumsuz bir ifadede yararlanabilir.
eyelidlessness

Chrome artık onu destekliyor gibi görünüyor.
Daniel X Moore

7

Aslında jquery yaklaşımı o kadar da kötü değil. Görmek:

http://docs.jquery.com/Events/error#fn

ve:

$(window).error(function(msg, url, line){
  $.post("js_error_log.php", { msg: msg, url: url, line: line });
});

11
bunu şimdi bulan herkes için - jquery aslında bir olayı window.error olayına bağlamamayı önerir - yukarıdaki belge bağlantısına bakın. Extract: Pencere nesnesine bir jQuery error olayı işleyicisi eklenmemelidir. [...] Bunun yerine window.onerror kullanın.
zcrar70

ofc bu şekilde bağlanmaması gerekiyor, mantıksız! Bu teklif verildiğinde birçok hata meydana gelebilir (eğer başarılı bir şekilde yapıldıysa bile ...)
vsync

6

Kendi istisna işleyicinizle tüm istisnaları yakalayın ve instanceof kullanın.

$("inuput").live({
    click : function (event) {
        try {
            if (somethingGoesWrong) {
                throw new MyException();
            }
        } catch (Exception) {
            new MyExceptionHandler(Exception);
        }

    }
});

function MyExceptionHandler(Exception) {
    if (Exception instanceof TypeError || 
        Exception instanceof ReferenceError || 
        Exception instanceof RangeError ||  
        Exception instanceof SyntaxError ||     
        Exception instanceof URIError ) {
        throw Exception; // native error
     } else {
         // handle exception
     }
}

MyExcetpionHandler, dene-yakala bloğu olmadığından yerel hata atar.

Http://www.nczonline.net/blog/2009/03/10/the-art-of-throwing-javascript-errors-part-2/ adresini ziyaret edin


4

try-catchher zaman en iyi çözüm değildir. Örneğin, Chrome 7.0'da, konsol penceresindeki güzel yığın izini kaybedersiniz. İstisnayı yeniden atmak yardımcı olmuyor. Yığın izlerini koruyan ve istisna durumunda tepki vermenize izin veren herhangi bir çözüm bilmiyorum .


2

Biraz çalışmayla, tüm tarayıcılarda makul ölçüde eksiksiz yığın izleri elde etmek mümkündür.

Modern Chrome ve Opera (yani, Blink oluşturma motorunu temel alan her şey), ErrorEvent ve için HTML 5 taslak spesifikasyonunu tam olarak destekler window.onerror. Bu tarayıcıların her ikisinde de kullanabilir window.onerrorveya (şaşırtıcı bir şekilde!) 'Error' olayını doğru şekilde bağlayabilirsiniz:

// Only Chrome & Opera pass the error object.
window.onerror = function (message, file, line, col, error) {
    console.log(message, "from", error.stack);
    // You can send data to your server
    // sendData(data);
};
// Only Chrome & Opera have an error attribute on the event.
window.addEventListener("error", function (e) {
    console.log(e.error.message, "from", e.error.stack);
    // You can send data to your server
    // sendData(data);
})

Ne yazık ki Firefox, Safari ve IE hala buralarda ve onları da desteklememiz gerekiyor. Stacktrace mevcut olmadığından window.onerrorbiraz daha fazla iş yapmalıyız.

Hatalardan yığın izleri elde etmek için yapabileceğimiz tek şeyin, tüm kodumuzu bir try{ }catch(e){ }Hatalardan yığın izleri bloğa ve ardından e.stack'e bakmak olduğu ortaya çıktı. Bir işlevi alan ve iyi bir hata işleme ile yeni bir işlev döndüren wrap adlı bir işlevle süreci biraz daha kolaylaştırabiliriz.

function wrap(func) {
    // Ensure we only wrap the function once.
    if (!func._wrapped) {
        func._wrapped = function () {
            try{
                func.apply(this, arguments);
            } catch(e) {
                console.log(e.message, "from", e.stack);
                // You can send data to your server
                // sendData(data);
                throw e;
            }
        }
    }
    return func._wrapped;
};

Bu çalışıyor. El ile sardığınız herhangi bir işlev, iyi bir hata işlemeye sahip olacaktır.

Aşağıdaki gibi görüntü etiketi kullanarak veri gönderebilirsiniz

function sendData(data) {
    var img = newImage(),
        src = http://yourserver.com/jserror + '&data=' + encodeURIComponent(JSON.stringify(data));

    img.crossOrigin = 'anonymous';
    img.onload = function success() {
        console.log('success', data);
    };
    img.onerror = img.onabort = function failure() {
        console.error('failure', data);
    };
    img.src = src;
}

Ancak, verileri toplamak için arka uç ve verileri görselleştirmek için ön uç yapmanız gerekir.

At Atatus , biz bu sorunu çözmeye çalışıyoruz. Hata izlemenin ötesinde, Atatus gerçek kullanıcı takibi sağlar.

Bir deneyin https://www.atatus.com/

Yasal Uyarı: Atatus'ta bir web geliştiricisiyim.


1

Modern tarayıcılarda, Ajax hataları için jQuery olay işleyicileri ekleyerek ve Ajax hataları için jQuery olay işleyicileri ekleyerek, en tepeye çıkan hatalar için window.onerror'ı çengellemenin, istemci kodunuzda atılan tüm Hata nesnelerini yakalayacağı doğrudur. Window.onerror için manuel olarak bir işleyici kuruyorsanız, modern tarayıcılarda bu işlem yapılır window.addEventListener('error', callback), IE8 / 9'da ise aramanız gerekir window.attachEvent('onerror', callback).

Daha sonra bu hataların işlendiği ortamı ve bunun nedenini göz önünde bulundurmanız gerektiğini unutmayın. Yığın izleriyle mümkün olduğunca çok hatayı yakalamak bir şeydir, ancak modern F12 geliştirme araçlarının ortaya çıkışı, yerel olarak uygularken ve hata ayıklarken bu kullanım durumunu çözer. Kesme noktaları vb., Özellikle CORS isteklerinden yüklenen üçüncü taraf kitaplıkları tarafından atılan hatalar için işleyicilerde bulunandan daha fazla veri sağlar. Tarayıcıya bu verileri sağlama talimatı vermek için ek adımlar atmanız gerekir.

Temel sorun, bu verileri üretimde sağlamaktır, çünkü kullanıcılarınızın muhtemelen test edebileceğinizden çok daha geniş bir tarayıcı ve sürüm dizisi çalıştırması garanti edilir ve siteniz / uygulamanız, ne kadar QA atarsanız verin beklenmedik şekillerde bozulacaktır. o.

Bunu halletmek için, kodunuzu kullandıklarında kullanıcınızın tarayıcılarına atılan her hatayı toplayan ve bunları, verileri sizin tarafınızdan görülebileceği ve hataları meydana geldikçe düzeltmek için kullanılabileceği bir uç noktaya gönderen bir üretim hatası izleyicisine ihtiyacınız vardır. . Raygun'da (sorumluluk reddi: Raygun'da çalışıyorum) bunun için harika bir deneyim sağlamak için çok çaba sarf ettik, çünkü saf bir uygulamanın gözden kaçırılacağını düşünmemiz gereken pek çok tuzak ve sorun var.

Örneğin, JS varlıklarınızı bir araya getirme ve küçültme ihtimaliniz vardır; bu, küçültülmüş koddan atılan hataların, karıştırılmış değişken adlarına sahip önemsiz yığın izlerine sahip olacağı anlamına gelir. Bunun için, kaynak haritaları oluşturmak için derleme aracınıza ihtiyacınız var (ardışık düzeninin bu bölümü için UglifyJS2'yi öneriyoruz) ve hata izleyicinizin bunları kabul edip işleyerek karıştırılmış yığın izlerini tekrar insan tarafından okunabilir hale getirmesi için. Raygun, tüm bunları kutudan çıkarır ve inşa süreciniz tarafından oluşturulduğunda kaynak haritalarını kabul etmek için bir API uç noktası içerir. Bu, halka açık olmamaları gerektiği için anahtardır, aksi takdirde herhangi biri kodunuzu küçültebilir ve amacını reddedebilir.

Raygun4js istemci kütüphanesi de birlikte geliyor window.onerrorjQuery dışı-box kanca şekilde ekleyebilmek için gereken Bunu ayarlamak için, hem de, hem modern hem de eski tarayıcılar için:

<script type="text/javascript" src="//cdn.raygun.io/raygun4js/raygun.min.js" </script> <script> Raygun.init('yourApiKey').attach(); </script>

Ayrıca, hata yükünü gönderilmeden önce değiştirebilme, etiket ve özel veriler, hatayı gören kullanıcıyla ilgili meta veriler ekleme gibi yerleşik bir dizi işlevsellik de vardır. Aynı zamanda, yukarıda belirtilen üçüncü taraf CORS komut dosyalarından iyi yığın izleri elde etmenin acısını da ortadan kaldırır, bu da korkunç 'Komut Dosyası Hatası'nı (hata mesajı ve yığın izi içermeyen) çözer.

Daha önemli bir sorun, web'deki geniş kitle nedeniyle sitenizin her hatanın binlerce kopyasını oluşturmasıdır. Raygun gibi bir hata izleme hizmeti , bunları hata gruplarına ayıracak akıllı özelliklere sahiptir, böylece bir bildirim selinde boğulmazsınız ve her gerçek hatayı düzeltilmeye hazır olarak görmenizi sağlar.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.