Bahan, terjemahan yang kami terbitkan hari ini, didedikasikan untuk menangani kesalahan JS menggunakan
window.onerror
. Ini adalah acara browser khusus yang dipicu ketika terjadi kesalahan yang tidak tertangkap. Di sini kita akan berbicara tentang cara untuk menangkap kesalahan menggunakan
onerror
peristiwa
onerror
, dan cara mengirim informasi tentang mereka ke server pengembang situs web. Handler ini dapat digunakan sebagai dasar sistem Anda sendiri untuk mengumpulkan dan menganalisis informasi kesalahan. Selain itu, ini adalah salah satu mekanisme paling penting yang digunakan dalam perpustakaan berorientasi kesalahan, seperti
gagak .

Mendengarkan acara window.onerror
Anda dapat mendengarkan acara
onerror
dengan menetapkan
window.onerror
fungsi yang memainkan peran penangan kesalahan:
window.onerror = function(msg, url, lineNo, columnNo, error) { // ... ... return false; }
Fungsi ini dipanggil ketika kesalahan terjadi, argumen berikut diteruskan ke sana:
msg
- pesan kesalahan. Sebagai contoh, Uncaught ReferenceError: foo is not defined
.url
- alamat skrip atau dokumen tempat kesalahan terjadi. Misalnya, /dist/app.js
.lineNo
- nomor baris tempat kesalahan terjadi (jika didukung).columnNo
- nomor kolom baris (jika didukung).error
- objek error
(jika didukung).
Empat argumen pertama memberi tahu pengembang skrip mana, di baris mana, dan di kolom mana baris ini terjadi kesalahan. Argumen terakhir, objek bertipe
Error
, mungkin adalah argumen yang paling penting. Mari kita bicarakan.
Objek kesalahan dan properti Error.prototype.stack
Pada pandangan pertama, objek
Error
tidak ada yang istimewa. Ini berisi tiga properti standar -
message
,
fileName
, dan
lineNumber
. Data ini, mengingat informasi yang diteruskan ke
window.onerror
event handler, dapat dianggap berlebihan.
Nilai sebenarnya dalam kasus ini adalah properti
Error.prototype.stack
non-standar. Properti ini memberikan akses ke tumpukan panggilan (tumpukan kesalahan), memungkinkan Anda untuk mengetahui apa yang terjadi dalam program pada saat kesalahan terjadi, yang mana panggilan fungsi mendahului kemunculannya. Pelacakan tumpukan panggilan dapat menjadi bagian penting dari proses debugging. Dan, terlepas dari kenyataan bahwa properti
stack
tidak standar, itu tersedia di semua browser modern.
Inilah yang terlihat seperti properti
stack
objek kesalahan di Chrome 46.
"Error: foobar\n at new bar (<anonymous>:241:11)\n at foo (<anonymous>:245:5)\n at <anonymous>:250:5\n at <anonymous>:251:3\n at <anonymous>:267:4\n at callFunction (<anonymous>:229:33)\n at <anonymous>:239:23\n at <anonymous>:240:3\n at Object.InjectedScript.\_evaluateOn (<anonymous>:875:140)\n at Object.InjectedScript.\_evaluateAndWrap (<anonymous>:808:34)"
Di depan kami adalah string yang tidak diformat. Ketika konten properti ini disajikan dalam bentuk ini, tidak nyaman untuk bekerja dengannya. Begini cara yang sama akan terlihat setelah pemformatan.
Error: foobar at new bar (<anonymous>:241:11) at foo (<anonymous>:245:5) at callFunction (<anonymous>:229:33) at Object.InjectedScript._evaluateOn (<anonymous>:875:140) at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)
Sekarang, setelah memformat, tumpukan kesalahan terlihat jauh lebih jelas, segera menjadi jelas mengapa properti
stack
sangat penting ketika men-debug kesalahan.
Namun, di sini semuanya tidak berjalan lancar. Properti
stack
tidak distandarisasi, tetapi diimplementasikan secara berbeda di browser yang berbeda. Di sini, misalnya, adalah seperti apa tumpukan kesalahan terlihat di Internet Explorer 11.
Error: foobar at bar (Unknown script code:2:5) at foo (Unknown script code:6:5) at Anonymous function (Unknown script code:11:5) at Anonymous function (Unknown script code:10:2) at Anonymous function (Unknown script code:1:73)
Anda dapat melihat, dibandingkan dengan contoh sebelumnya, bahwa di sini tidak hanya format yang berbeda untuk mewakili bingkai tumpukan digunakan, tetapi juga bahwa ada lebih sedikit data untuk setiap bingkai. Misalnya, Chrome mengidentifikasi contoh penggunaan kata kunci
new
dan memberikan informasi lebih rinci tentang acara lain (khususnya, tentang panggilan fungsi.
_evaluateOn
dan.
_evaluateAndWrap
). Pada saat yang sama, di sini kami membandingkan hanya apa yang diberikan IE dan Chrome. Browser lain menggunakan pendekatan mereka sendiri untuk menampilkan data tentang stack dan untuk memilih informasi yang termasuk dalam data ini.
Agar semua ini terlihat seragam, Anda dapat menggunakan alat pihak ketiga. Sebagai contoh, gagak-js menggunakan TraceKit untuk ini. Stacktrace.js dan beberapa proyek lainnya memiliki tujuan yang sama.
Fitur window.onerror didukung oleh berbagai browser
Peristiwa
windows.onerror
telah ada di browser selama beberapa waktu. Secara khusus, dapat ditemukan di IE6 dan Firefox 2. Masalahnya di sini adalah bahwa semua browser menerapkan
windows.onerror
dengan cara yang berbeda. Misalnya, ini menyangkut jumlah dan struktur argumen yang diteruskan ke penangan acara ini.
Berikut adalah tabel yang
onerror
argumen yang diteruskan ke penangan
onerror
di peramban utama.
Browser
| pesan
| url
| lineTidak
| colNo
| errorObj
|
Firefox
| Ada
| Ada
| Ada
| Ada
| Ada
|
Chrome
| Ada
| Ada
| Ada
| Ada
| Ada
|
Edge
| Ada
| Ada
| Ada
| Ada
| Ada
|
IE 11
| Ada
| Ada
| Ada
| Ada
| Ada
|
IE10
| Ada
| Ada
| Ada
| Ada
| Tidak
|
IE 9.8
| Ada
| Ada
| Ada
| Tidak
| Tidak
|
Safari 10 ke atas
| Ada
| Ada
| Ada
| Ada
| Ada
|
Safari 9
| Ada
| Ada
| Ada
| Ada
| Tidak
|
Browser Android 4.4
| Ada
| Ada
| Ada
| Ada
| Tidak
|
Mungkin tidak mengherankan, Internet Explorer 8, 9, dan 10 memiliki dukungan terbatas untuk satu
onerror
. Namun, mungkin tampak tidak biasa bahwa dukungan browser Safari untuk objek kesalahan hanya muncul di versi 10, dirilis pada 2016. Selain itu, ada perangkat seluler lawas yang menggunakan browser Android standar, yang juga tidak mendukung objek kesalahan. Dalam versi modern Android, browser ini telah digantikan oleh Chrome Mobile.
Jika tidak ada objek kesalahan yang kami miliki, maka tidak ada data tentang jejak stack. Ini berarti bahwa browser yang tidak mendukung objek kesalahan tidak memberikan informasi tumpukan dalam skrip standar untuk menggunakan penangan
onerror
. Dan ini, seperti yang telah kami katakan, sangat penting.
Pengembangan polyfill untuk window.onerror menggunakan try / catch construct
Untuk mendapatkan informasi tentang tumpukan di browser yang tidak mendukung melewatkan objek
onerror
ke penangan
onerror
, Anda dapat menggunakan trik berikut. Anda bisa membungkus kode dalam konstruk
try/catch
-
try/catch
dan tangkap sendiri kesalahannya. Objek kesalahan yang dihasilkan akan berisi, di semua browser modern, yang kita butuhkan adalah properti
stack
.
Lihatlah kode metode helper
invoke()
, yang memanggil metode yang diberikan objek, memberikan array argumen.
function invoke(obj, method, args) { return obj[method].apply(this,args); }
Inilah cara menggunakannya.
invoke(Math, 'max', [1,2])
Berikut ini adalah
invoke()
sama
invoke()
, tetapi sekarang pemanggilan metode dibungkus
try/catch
, yang memungkinkan Anda untuk menangkap kemungkinan kesalahan.
function invoke(obj, method, args) { try { return obj[method].apply(this,args); } catch(e) { captureError(e);// throw e;// } } invoke(Math,'highest',[1,2]); // , Math.highest
Tentu saja, sangat mahal untuk menambahkan struktur seperti itu secara manual ke semua tempat yang mungkin membutuhkannya. Tugas ini dapat disederhanakan dengan membuat fungsi penolong universal.
function wrapErrors(fn) { // if(!fn.__wrapped__) { fn.__wrapped__ = function() { try{ return fn.apply(this,arguments); }catch(e){ captureError(e);// throw e;// } }; } return fn.__wrapped__; } var invoke = wrapErrors(function(obj, method, args) { returnobj[method].apply(this,args); }); invoke(Math,'highest',[1,2]);//, Math.highest
Karena JavaScript menggunakan model eksekusi kode berulir tunggal, pembungkus ini harus digunakan hanya dengan pemanggilan fungsi yang ada di awal tumpukan baru. Tidak perlu membungkus semua panggilan fungsi di dalamnya.
Akibatnya, ternyata fungsi ini harus digunakan di tempat-tempat berikut:
- Di mana aplikasi dimulai (misalnya, saat menggunakan jQuery, dalam fungsi
$(document).ready
) - Dalam penangan acara (misalnya, di
addEventListener
atau dalam konstruksi formulir $.fn.click
) - Dalam panggilan balik yang dipanggil oleh acara penghitung waktu (misalnya,
setTimeout
atau requestAnimationFrame
)
Berikut adalah contoh menggunakan fungsi
wrapErrors
.
$(wrapErrors(function () {// doSynchronousStuff1();// setTimeout(wrapErrors(function () { doSynchronousStuff2();// })); $('.foo').click(wrapErrors(function () { doSynchronousStuff3();// })); }));
Konstruksi seperti itu dapat ditambahkan ke kode sendiri, tetapi ini tugas yang terlalu memakan waktu. Sebagai alternatif yang nyaman dalam situasi seperti itu, Anda dapat mempertimbangkan perpustakaan untuk bekerja dengan kesalahan, yang, misalnya, memiliki mekanisme yang
addEventListener
dan
setTimeout
alat untuk
addEventListener
kesalahan.
Kesalahan transfer ke server
Jadi, sekarang kami memiliki sarana yang kami miliki untuk mencegat informasi kesalahan baik menggunakan
windows.onerror
atau menggunakan fungsi tambahan berdasarkan
try/catch
. Kesalahan ini terjadi di sisi klien, dan, setelah intersepsi mereka, kami ingin mengatasinya dan mengambil langkah-langkah untuk menghilangkannya. Untuk melakukan ini, mereka harus ditransfer ke server kami. Untuk melakukan ini, Anda perlu menyiapkan layanan web yang akan menerima informasi tentang kesalahan melalui HTTP, dan kemudian menyimpannya untuk diproses lebih lanjut, misalnya - akan menulis ke file log atau database.
Jika layanan web ini terletak pada domain yang sama dengan aplikasi web,
XMLHttpRequest
akan cukup. Contoh berikut menunjukkan cara menggunakan fungsi untuk menjalankan kueri AJAX dari jQuery untuk mentransfer data ke server.
function captureError(ex){ var errorData = { name:ex.name,// : ReferenceError message:ex.line,// : x is undefined url:document.location.href, stack:ex.stack// ; , ! }; $.post('/logger/js/',{ data:errorData }); }
Perlu diingat bahwa jika Anda perlu mengirim permintaan lintas-domain untuk mengirim informasi tentang kesalahan ke server, Anda harus berhati-hati mendukung permintaan tersebut.
Ringkasan
Anda telah mempelajari dasar-dasar membuat layanan untuk menangkap kesalahan dan mengirim informasi tentangnya ke server. Secara khusus, di sini kami memeriksa masalah berikut:
- Fitur acara
onerror
dan dukungannya di berbagai browser. - Menggunakan mekanisme
try/catch
untuk mendapatkan informasi tentang tumpukan panggilan dalam kasus-kasus di mana onerror
tidak mendukung bekerja dengan objek kesalahan. - Transfer data kesalahan ke server pengembang.
Setelah mempelajari tentang bagaimana mekanisme di atas bekerja, Anda telah memperoleh pengetahuan dasar yang akan memungkinkan Anda untuk mulai membuat sistem Anda sendiri untuk bekerja dengan kesalahan, mengklarifikasi detail tambahan selama bekerja. Mungkin skenario ini sangat relevan untuk kasus-kasus ketika datang ke aplikasi tertentu di mana, katakanlah, untuk alasan keamanan, itu tidak direncanakan untuk menggunakan perpustakaan pihak ketiga. Jika aplikasi Anda memungkinkan penggunaan kode pihak ketiga, Anda dapat menemukan alat yang tepat untuk memonitor kesalahan JS. Di antara alat-alat tersebut adalah
Sentry ,
Rollbar ,
TrackJS dan proyek serupa lainnya.
Pembaca yang budiman! Alat apa untuk memantau kesalahan JS yang Anda gunakan?
