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 diri kami sendiri throw new Error()
yang tentu saja dapat kami tangkap jika kami ingin menangkap, karena kami tahu betul di mana throw
ditulis. 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.
Jika beberapa API browser diketahui melemparkan pengecualian, kita perlu melakukan panggilan ke dalam try-catch
untuk menghindari seluruh program memasuki keadaan ilegal karena kesalahan. Misalnya, window.localStorage
adalah API seperti itu.
try {
localstorage.setitem ('date', date.now ());
} catch (error) {
reporterror (kesalahan);
}
Skenario yang berlaku try-catch
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 try-catch
.
listeners.forEach(function(listener) {
mencoba {
pendengar();
} catch (error) {
reporterror (kesalahan);
}
});
Untuk tempat-tempat yang tidak dapat dicakup oleh try-catch
, jika terjadi pengecualian, itu hanya dapat ditangkap melalui window.onerror
.
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
.
Misalkan kita memiliki fungsi reportError
untuk mengumpulkan pengecualian yang tertangkap dan kemudian mengirimkannya dalam batch ke penyimpanan sisi server untuk kueri dan analisis, lalu informasi apa yang ingin kita kumpulkan? Informasi yang lebih berguna meliputi: Jenis kesalahan ( name
), pesan kesalahan ( message
), alamat file skrip ( script
), nomor baris ( line
), nomor kolom ( column
), dan stack trace ( stack
). Jika pengecualian ditangkap melalui try-catch
, semua informasi ini ada pada objek Error
(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 tak terduga dari 3 parameter ini hilang.
Jika objek Error
dibuat sendiri, maka error.message
. message
dasarnya, apa yang kita masukkan ke dalam error.message
window.onerror
(Browser sebenarnya akan membuat sedikit dimodifikasi, seperti menambahkan 'Uncaught Error: '
awalan.) Oleh karena itu, kita dapat membuat serialisasi atribut yang kita khawatirkan (seperti JSON.Stringify
) dan menyimpannya dalam error.message
mereka di window.onerror
Tentu saja, ini terbatas pada objek Error
yang kita buat sendiri.
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 Error
di parameter kelima, dan Anda dapat membaca atribut apa pun, termasuk atribut khusus. Akibatnya, Chrome bergerak lebih cepat, window.onerror
baru. Tanda tangan diimplementasikan di Chrome 30, menghasilkan penulisan draft standar berikut.
Keteraturan atributwindow.onerror = function(
errormessage,
scripturi,
linenumber,
ColumnNumber,
kesalahan
) {
if (error) {
reporterror (kesalahan);
} kalau tidak {
reporterror ({
Pesan: ErrorMessage,
Script: Scripturi,
Baris: linenumber,
Kolom: ColumnNumber
});
}
}
Nama -nama atribut objek Error
yang Error
bahas sebelumnya script
pada metode penamaan filename
. Oleh karena itu, kami juga memerlukan fungsi khusus untuk menormalkan objek Error
, 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.
Mirip adalah format jejak stack
. Properti ini menyimpan informasi tumpukan pengecualian ketika itu terjadi dalam bentuk teks biasa. Nama ( identifier
), file ( script
), nomor baris ( line
) dan nomor kolom ( column
).
Jika Anda juga mengalami kesalahan dengan pesan 'Script error.'
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 script.src
Atribut script.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 'Script error.'
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 'Script error.'
yang tidak berguna.
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:
<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 urutan 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 <script>
:
<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 scheduleRemoteScript
dan scheduleInlineScript
, 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 code
yang lebih besar. Fungsi code
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 scheduleRemoteScript
berdasarkan alamat dan kode yang langsung diperoleh dengan scheduleInlineScript
dapat dieksekusi satu per satu dalam urutan yang benar. Saya tidak akan memberikan kode terperinci di sini.
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 error.script
, dan kemudian nomor baris yang unik dapat ditempatkan melalui error.line
. Sekarang, karena <script>
kode yang tertanam di halaman, beberapa tag <script>
tidak dapat dibedakan dengan error.script
. 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, maka saya dapat membiarkan kode dalam tag <script>
pertama mengambil baris 11000 dan biarkan <script>
kedua tag dalam kode dalam kode Menempati baris 10012000 (1000 garis kosong dimasukkan sebelum dimasukkan), kode tag <script>
ketiga menempati garis 20013000 (garis 2000 kosong dimasukkan sebelum dimasukkan), dan sebagainya. Kemudian kami menggunakan atribut data-*
untuk merekam informasi ini agar mudah memeriksa kembali.
<script
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 error.line
adalah 3005
, itu berarti kesalahan yang sebenarnya. error.script
harus 'http://cdn.com/step3.js'
, sedangkan error.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 1000 baris untuk setiap 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.
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 <img>
. Jika tag <img>
adalah sumber yang berbeda, yang pernah digunakan dalam gambar <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 <img>
memecahkan masalah ini dengan memperkenalkan atribut crossorigin
. Jika crossorigin="anonymous"
digunakan, itu setara dengan CORS anonim; jika crossorigin = "penggunaan-kredensial" digunakan, itu setara dengan CORS bersertifikat.
Karena tag <img>
dapat melakukan ini, mengapa tag <script>
tidak dapat melakukan ini? Oleh karena itu, 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="anonymous"
sebagai crossorigin="use-credentials"
, 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.
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.