Cara menangkap dan menganalisis kesalahan javascript
Insinyur front-end semua tahu bahwa JavaScript memiliki kemampuan penanganan pengecualian dasar. Kita dapat melempar kesalahan baru (), dan browser juga akan melempar pengecualian saat kita memanggil kesalahan API. Tetapi diperkirakan bahwa sebagian besar insinyur front-end belum mempertimbangkan mengumpulkan informasi luar biasa ini. Ngomong -ngomong, selama penyegaran gagal mereproduksi setelah kesalahan JavaScript, pengguna dapat menyelesaikan masalah dengan menyegarkan, dan browser tidak akan macet, dan akan baik -baik saja jika belum terjadi. Asumsi ini benar sebelum aplikasi satu halaman menjadi populer. Aplikasi satu halaman saat ini sangat kompleks setelah berjalan untuk jangka waktu tertentu. Tidakkah Anda benar -benar mengerjakan ulang operasi sebelumnya? Jadi masih perlu bagi kami untuk menangkap dan menganalisis informasi pengecualian ini, dan kemudian kami dapat memodifikasi kode untuk menghindari mempengaruhi pengalaman pengguna.
Cara menangkap pengecualian
Kami menulis sendiri kesalahan baru (). Namun, pengecualian yang terjadi ketika memanggil API browser tidak selalu mudah ditangkap. Untuk yang pertama kita juga dapat menangkapnya melalui TRY-Catch, untuk yang terakhir kita harus mendengarkan pengecualian global dan kemudian menangkapnya.
Cobalah tangkapan
Jika beberapa API browser diketahui melemparkan pengecualian, kita perlu melakukan panggilan ke dalam mencoba-cat untuk menghindari seluruh program memasuki keadaan ilegal karena kesalahan. Misalnya, Window.LocalStorage adalah API seperti itu.
Salinan kode adalah sebagai berikut:
mencoba {
localstorage.setitem ('date', date.now ());
} catch (error) {
reporterror (kesalahan);
}
Skenario yang berlaku untuk mencoba-tangkapan umum adalah panggilan balik. Karena kode fungsi callback tidak terkendali, kami tidak tahu seberapa baik kode itu, dan apakah API lain yang melempar pengecualian akan dipanggil. Agar tidak menyebabkan kode lain dieksekusi setelah memanggil panggilan balik karena kesalahan panggilan balik, perlu untuk mengembalikan panggilan ke dalam mencoba-tangkapan.
Salinan kode adalah sebagai berikut:
listeners.foreach (function (listener) {
mencoba {
pendengar();
} catch (error) {
reporterror (kesalahan);
}
});
window.onerror
Untuk tempat-tempat yang tidak dapat dicakup oleh TRY-Catch, jika terjadi pengecualian, itu hanya dapat ditangkap melalui Window.onerror.
Salinan kode adalah sebagai berikut:
window.onError =
fungsi (errorMessage, scripturi, linenumber) {
reporterror ({
Pesan: ErrorMessage,
Script: Scripturi,
Baris: LinenBer
});
}
Berhati -hatilah untuk tidak pintar dan menggunakan window.addeventlistener atau window.attachevent untuk mendengarkan window.onerror. Banyak browser hanya mengimplementasikan window.onerror, atau hanya implementasi window.onerror adalah standar. Mempertimbangkan bahwa draft standar juga mendefinisikan window.onerror, kita hanya perlu menggunakan window.onerror.
Properti hilang
Misalkan kita memiliki fungsi reporterror untuk mengumpulkan pengecualian yang tertangkap dan kemudian mengirimkannya dalam batch ke penyimpanan sisi server untuk kueri dan analisis, informasi apa yang ingin kita kumpulkan? Informasi yang lebih berguna meliputi: Jenis kesalahan (nama), pesan kesalahan (pesan), alamat file skrip (skrip), nomor baris (baris), nomor kolom (kolom), dan stack trace. Jika pengecualian ditangkap melalui TRY-Catch, semua informasi ini ada pada objek kesalahan (didukung oleh browser arus utama), sehingga Reporterror juga dapat mengumpulkan informasi ini. Tetapi jika ditangkap melalui Window.onerror, kita semua tahu bahwa fungsi acara ini hanya memiliki 3 parameter, sehingga informasi selain dari 3 parameter ini hilang.
Membuat serial pesan
Jika objek kesalahan dibuat sendiri, maka kesalahan. Pada dasarnya, apa yang kita masukkan ke dalam kesalahan. (Browser sebenarnya membuat sedikit modifikasi, seperti menambahkan 'kesalahan yang tidak dibawa:' awalan.) Oleh karena itu, kita dapat membuat serialisasi atribut yang kita khawatirkan (seperti json.stringify) dan simpan dalam kesalahan. mereka di jendela. Tentu saja, ini terbatas pada objek kesalahan yang kami buat sendiri.
Parameter kelima
Produsen browser juga mengetahui pembatasan yang dikenakan orang saat menggunakan Window.onerror, sehingga mereka mulai menambahkan parameter baru ke window.onerror. Mempertimbangkan bahwa hanya nomor baris dan tidak ada nomor kolom yang tampaknya sangat simetris, yaitu pertama -tama menambahkan nomor kolom dan menempatkannya di parameter keempat. Namun, yang lebih diperhatikan semua orang adalah apakah mereka bisa mendapatkan tumpukan lengkap, jadi Firefox mengatakan akan lebih baik untuk meletakkan tumpukan di parameter kelima. Tetapi Chrome mengatakan bahwa akan lebih baik untuk menempatkan seluruh objek kesalahan di parameter kelima. Akibatnya, karena Chrome lebih cepat, tanda tangan baru. Tanda tangan diimplementasikan di Chrome 30, menghasilkan penulisan draft standar berikut.
Salinan kode adalah sebagai berikut:
window.onError = function (
errormessage,
scripturi,
linenumber,
ColumnNumber,
kesalahan
) {
if (error) {
reporterror (kesalahan);
} kalau tidak {
reporterror ({
Pesan: ErrorMessage,
Script: Scripturi,
Baris: linenumber,
Kolom: ColumnNumber
});
}
}
Keteraturan atribut
Nama -nama properti objek kesalahan yang kita bahas sebelumnya didasarkan pada metode penamaan chrome. Oleh karena itu, kami juga memerlukan fungsi khusus untuk menormalkan objek kesalahan, yaitu memetakan nama atribut yang berbeda ke nama atribut terpadu. Untuk praktik tertentu, silakan merujuk ke artikel ini. Meskipun implementasi browser akan diperbarui, tidak akan terlalu sulit bagi siapa pun untuk mempertahankan tabel pemetaan seperti itu.
Serupa adalah format jejak tumpukan. Properti ini menyimpan informasi tumpukan pengecualian ketika itu terjadi dalam bentuk teks biasa. nama (pengidentifikasi), file (skrip), baris (baris) dan kolom (kolom).
Keterbatasan Keamanan
Jika Anda juga mengalami kesalahan dengan pesan 'kesalahan skrip.', Anda akan memahami apa yang saya bicarakan, yang sebenarnya merupakan batasan browser untuk file skrip dari berbagai sumber. Alasan pembatasan keamanan ini adalah sebagai berikut: Misalkan HTML dikembalikan oleh bankir online setelah masuk berbeda dari HTML yang dilihat oleh pengguna anonim, situs web pihak ketiga dapat memasukkan URI dari bank online ini ke dalam skrip. Atribut SRC. Tentu saja, HTML tidak dapat diuraikan sebagai JS, sehingga browser akan melempar pengecualian, dan situs web pihak ketiga ini dapat menentukan apakah pengguna masuk dengan menganalisis lokasi pengecualian. Untuk alasan ini, browser menyaring semua pengecualian yang dilemparkan oleh file skrip sumber yang berbeda, hanya menyisakan pesan yang tidak berubah seperti 'kesalahan skrip.', Dan semua atribut lainnya menghilang.
Untuk situs web skala tertentu, adalah normal untuk file skrip ditempatkan pada CDN dan sumber yang berbeda ditempatkan. Sekarang bahkan jika Anda membuat situs web kecil sendiri, kerangka kerja umum seperti jQuery dan Backbone dapat secara langsung merujuk versi pada CDN publik untuk mempercepat unduhan pengguna. Jadi pembatasan keamanan ini menyebabkan beberapa masalah, menyebabkan informasi pengecualian yang kami kumpulkan dari Chrome dan Firefox menjadi 'kesalahan skrip' yang tidak berguna.
CORS
Jika Anda ingin melewati batasan ini, cukup pastikan bahwa file skrip dan halaman itu sendiri sama. Tetapi bukankah menempatkan file skrip di server yang tidak dipercepat oleh CDN mengurangi kecepatan unduhan pengguna? Salah satu solusi adalah terus menempatkan file skrip pada CDN, gunakan XMLHTTPREQUEST untuk mengunduh konten kembali melalui CORS, dan kemudian membuat tag <script> untuk menyuntikkannya ke halaman. Kode yang tertanam di halaman tentu saja asal yang sama.
Ini mudah dikatakan, tetapi ada banyak detail untuk diimplementasikan. Untuk memberikan contoh sederhana:
Salinan kode adalah sebagai berikut:
<Script src = "http://cdn.com/step1.js"> </script>
<script>
(function step2 () {}) ();
</script>
<Script src = "http://cdn.com/step3.js"> </script>
Kita semua tahu bahwa jika ada dependensi dalam Langkah1, Langkah2, dan Langkah3, itu harus dieksekusi secara ketat dalam urutan ini, jika tidak kesalahan dapat terjadi. Browser dapat meminta file Step1 dan Step3 secara paralel, tetapi pesanan dijamin saat dieksekusi. Jika kami mendapatkan konten file dari Step1 dan Step3 dengan menggunakan XMLHTTPREQUEST, kita perlu memastikan pesanan yang benar sendiri. Selain itu, jangan lupa Step2.
Jika kami sudah memiliki satu set alat lengkap untuk menghasilkan tag <script> untuk berbagai halaman di situs web, kami perlu menyesuaikan set alat ini untuk membuat perubahan pada tag <ript>:
Salinan kode adalah sebagai berikut:
<script>
scheduleremotescript ('http://cdn.com/step1.js');
</script>
<script>
JadwalInLinescript (kode fungsi () {
(function step2 () {}) ();
});
</script>
<script>
scheduleremotescript ('http://cdn.com/step3.js');
</script>
Kita perlu mengimplementasikan dua fungsi jadwaleMoteScript dan jadwal inline, dan memastikan bahwa mereka didefinisikan sebelum tag <script> pertama yang merujuk pada file skrip eksternal, dan kemudian tag <script> yang tersisa akan ditulis ulang ke dalam bentuk di atas. Perhatikan bahwa fungsi Step2 yang dieksekusi segera ditempatkan dalam fungsi kode yang lebih besar. Fungsi kode tidak akan dieksekusi, itu hanya sebuah wadah, sehingga kode Step2 asli dapat dipertahankan tanpa melarikan diri, tetapi tidak akan segera dieksekusi.
Selanjutnya, kita perlu mengimplementasikan mekanisme lengkap untuk memastikan bahwa konten file yang diunduh oleh SCRECTEREReMoteScript berdasarkan alamat dan kode yang langsung diperoleh dengan JadwalinScript dapat dieksekusi satu per satu dalam urutan yang benar. Saya tidak akan memberikan kode terperinci di sini.
Cek nomor baris
Mendapatkan konten melalui CORS dan menyuntikkan kode ke dalam halaman dapat menembus pembatasan keamanan, tetapi akan memperkenalkan masalah baru, yaitu, konflik nomor baris. Awalnya, file skrip unik dapat ditempatkan melalui kesalahan. Script, dan kemudian nomor baris yang unik dapat ditempatkan melalui error.line. Sekarang, karena semua kode yang tertanam di halaman, beberapa tag <script> tidak dapat dibedakan dengan kesalahan. Namun, nomor baris di dalam setiap tag <script> dihitung dari 1, yang membuat kita tidak mungkin menggunakannya untuk menggunakannya Lokasi kode sumber di mana informasi pengecualian berada.
Untuk menghindari konflik nomor baris, kita dapat menyia -nyiakan beberapa nomor baris sehingga interval nomor baris yang digunakan oleh kode aktual di masing -masing tag <script> tidak tumpang tindih satu sama lain. Misalnya, dengan asumsi bahwa kode aktual di setiap tag <script> tidak melebihi 1000 baris, saya dapat membuat kode di tag <script> pertama mengambil baris 11000 dan tag kedua <script> Kode dalam kode menempati baris 10012000 (1000 baris kosong dimasukkan sebelum dimasukkan), kode tag <script> ketiga menempati baris 20013000 (2000 garis kosong dimasukkan sebelum dimasukkan), dan sebagainya. Kemudian kami menggunakan atribut data-* untuk merekam informasi ini agar mudah memeriksa kembali.
Salinan kode adalah sebagai berikut:
<skrip
data-src = "http://cdn.com/step1.js"
data-line-start = "1"
>
// Kode untuk Langkah 1
</script>
<skrip data-line-start = "1001">
// '/n' * 1000
// Kode untuk Langkah 2
</script>
<skrip
data-src = "http://cdn.com/step3.js"
data-line-start = "2001"
>
// '/n' * 2000
// Kode untuk Langkah 3
</script>
Setelah pemrosesan ini, jika kesalahan kesalahan. Garis adalah 3005, itu berarti kesalahan yang sebenarnya. Script harus 'http://cdn.com/step3.js', sedangkan kesalahan.line yang sebenarnya harus 5. Kami dapat menyelesaikan Nomor Baris ini Periksa terbalik dalam fungsi reporterror yang disebutkan sebelumnya.
Tentu saja, karena kami tidak dapat menjamin bahwa setiap file skrip hanya memiliki 1000 baris, ada kemungkinan bahwa beberapa file skrip secara signifikan kurang dari 1000 baris, sehingga tidak perlu secara tetap mengalokasikan interval baris 1000 untuk masing -masing tag <script>. Kami dapat mengalokasikan interval berdasarkan jumlah aktual baris skrip, cukup pastikan bahwa interval yang digunakan oleh masing -masing tag <script> tidak tumpang tindih.
Atribut Crossorigin
Pembatasan keamanan yang dikenakan oleh browser pada konten dari berbagai sumber tentu saja tidak terbatas pada tag <script>. Karena XMLHTTPREQUEST dapat menembus batasan ini melalui CORS, mengapa sumber daya dirujuk secara langsung melalui tag yang tidak diizinkan? Ini pasti ok.
Keterbatasan merujuk pada file skrip sumber yang berbeda untuk tag <script> juga berlaku untuk mengacu pada file gambar sumber yang berbeda untuk tag <mmg>. Jika tag <mmg> adalah sumber yang berbeda, yang pernah digunakan dalam gambar <an Canvas>, <Canvas> akan menjadi keadaan hanya menulis, memastikan bahwa situs web tidak dapat mencuri data gambar yang tidak sah dari berbagai sumber melalui JavaScript. Kemudian, tag <mmg> memecahkan masalah ini dengan memperkenalkan atribut crossorigin. Jika crossorigin = "Anonim", itu setara dengan CORS anonim;
Karena tag <mmg> dapat melakukan ini, mengapa tag <script> tidak dapat melakukan ini? Jadi produsen browser menambahkan atribut crossorigin yang sama ke tag <script> untuk menyelesaikan pembatasan keamanan di atas. Sekarang dukungan Chrome dan Firefox untuk properti ini sepenuhnya gratis. Safari akan memperlakukan crossorigin = "anonim" sebagai crossorigin = "penggunaan-kredensial", dan hasilnya adalah jika server hanya mendukung COR anonim, Safari akan memperlakukan otentikasi sebagai kegagalan. Karena server CDN dirancang hanya untuk mengembalikan konten statis untuk alasan kinerja, tidak mungkin untuk secara dinamis mengembalikan header HTTP yang diperlukan untuk mengotentikasi COR berdasarkan permintaan.
Meringkaskan
Penanganan pengecualian JavaScript terlihat sederhana dan tidak berbeda dengan bahasa lain, tetapi tidak mudah untuk menangkap semua pengecualian dan menganalisis properti. Meskipun beberapa layanan pihak ketiga sekarang menyediakan layanan Google Analytics yang menangkap pengecualian JavaScript, jika Anda ingin memahami detail dan prinsip, Anda harus melakukannya sendiri.