Brauzer bizga tashqi resurslarning yuklanishini kuzatish imkonini beradi – skriptlar, iframe’lar, rasmlar va hokazo.
Buning uchun ikkita hodisa mavjud:
onload– muvaffaqiyatli yuklash,onerror– xatolik yuz berdi.
Skriptni yuklash
Aytaylik, bizga uchinchi tomon skriptini yuklash va u erdagi funksiyani chaqirish kerak.
Biz uni dinamik ravishda yuklashimiz mumkin:
let script = document.createElement('script');
script.src = "my.js";
document.head.append(script);
Lekin shu skript ichida e’lon qilingan funksiyani qanday ishga tushiramiz? Skript yuklanishini kutishimiz va faqat shundan keyin uni chaqirishimiz kerak.
O’zimizning skriptlarimiz uchun JavaScript modullaridan foydalanishimiz mumkin, lekin ular uchinchi tomon kutubxonalari tomonidan keng qo’llanilmaydi.
script.onload
Asosiy yordamchi load hodisasidir. U skript yuklangan va bajarilgandan keyin ishga tushadi.
Masalan:
let script = document.createElement('script');
// har qanday skriptni, har qanday domendan yuklash mumkin
script.src = "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.3.0/lodash.js"
document.head.append(script);
script.onload = function() {
// skript "_" o'zgaruvchisini yaratadi
alert( _.VERSION ); // kutubxona versiyasini ko'rsatadi
};
Shunday qilib, onload da biz skript o’zgaruvchilarini ishlatishimiz, funksiyalarni ishga tushirishimiz va hokazolarni qilishimiz mumkin.
Va agar yuklash muvaffaqiyatsiz bo’lsa-chi? Masalan, bunday skript yo’q (404 xatolik) yoki server ishlamaydi (mavjud emas).
script.onerror
Skriptni yuklash vaqtida yuz beradigan xatoliklarni error hodisasida kuzatish mumkin.
Masalan, mavjud bo’lmagan skriptni so’rab ko’ramiz:
let script = document.createElement('script');
script.src = "https://example.com/404.js"; // bunday skript yo'q
document.head.append(script);
script.onerror = function() {
alert("Xatolik yuz berdi: " + this.src); // Xatolik yuz berdi: https://example.com/404.js
};
E’tibor bering, biz bu yerda HTTP xatolik tafsilotlarini ola olmaymiz. 404 yoki 500 yoki boshqa narsa ekanligini bilmaymiz. Faqat yuklanishning muvaffaqiyatsiz ekanligini bilamiz.
onload/onerror hodisalari faqat yuklanishning o’zini kuzatadi.
Skriptni qayta ishlash va bajarish vaqtida yuz berishi mumkin bo’lgan xatoliklar bu hodisalar doirasidan tashqarida. Ya’ni: agar skript muvaffaqiyatli yuklangan bo’lsa, onload ishga tushadi, hatto unda dasturlash xatoliklari bo’lsa ham. Skript xatoliklarini kuzatish uchun window.onerror global ishlov beruvchisidan foydalanish mumkin.
Boshqa resurslar
load va error hodisalari boshqa resurslar uchun ham ishlaydi, asosan tashqi src ga ega bo’lgan har qanday resurs uchun.
Masalan:
let img = document.createElement('img');
img.src = "https://js.cx/clipart/train.gif"; // (*)
img.onload = function() {
alert(`Rasm yuklandi, o'lchami ${img.width}x${img.height}`);
};
img.onerror = function() {
alert("Rasmni yuklashda xatolik yuz berdi");
};
Ba’zi eslatmalar mavjud:
- Ko’pgina resurslar hujjatga qo’shilganda yuklashni boshlaydi. Lekin
<img>istisno. Usrcni olganda yuklashni boshlaydi(*). <iframe>uchun,iframe.onloadhodisasi iframe yuklash tugaganda ishga tushadi, ham muvaffaqiyatli yuklash uchun, ham xatolik holatida.
Bu tarixiy sabablarga ko’ra.
Crossorigin siyosati
Qoida mavjud: bir saytdagi skriptlar boshqa saytning mazmuniga kira olmaydi. Masalan, https://facebook.com dagi skript https://gmail.com dagi foydalanuvchi pochta qutisini o’qiy olmaydi.
Yoki aniqroq qilib aytganda, bir manba (domen/port/protokol uchligi) boshqasining mazmuniga kira olmaydi. Shuning uchun subdomen yoki boshqa port bo’lsa ham, bular bir-biriga kirish huquqi bo’lmagan turli manbalar.
Bu qoida boshqa domenlardan kelgan resurslar uchun ham amal qiladi.
Agar biz boshqa domendagi skriptdan foydalansak va unda xatolik bo’lsa, xatolik tafsilotlarini ola olmaymiz.
Masalan, bitta (noto’g’ri) funksiya chaqiruvidan iborat error.js skriptini olamiz:
// 📁 error.js
noSuchFunction();
Endi uni joylashgan saytdan yuklaymiz:
<script>
window.onerror = function(message, url, line, col, errorObj) {
alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script src="/article/onload-onerror/crossorigin/error.js"></script>
Yaxshi xatolik hisobotini ko’rishimiz mumkin:
Uncaught ReferenceError: noSuchFunction is not defined
https://javascript.info/article/onload-onerror/crossorigin/error.js, 1:1
Endi xuddi shu skriptni boshqa domendan yuklaymiz:
<script>
window.onerror = function(message, url, line, col, errorObj) {
alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>
Hisobot boshqacha bo’ladi:
Script error.
, 0:0
Tafsilotlar brauzerga qarab farq qilishi mumkin, lekin g’oya bir xil: skriptning ichki ma’lumotlari, jumladan xatolik stack trace’lari yashirilgan. Aynan boshqa domendan bo’lgani uchun.
Nega bizga xatolik tafsilotlari kerak?
window.onerror yordamida global xatoliklarni tinglaydigan, xatoliklarni saqlaydigan va ularga kirish va tahlil qilish interfeysini taqdim etadigan ko’plab xizmatlar mavjud (va biz o’zimiznikini qura olamiz). Bu ajoyib, chunki biz foydalanuvchilarimiz tomonidan yuzaga kelgan haqiqiy xatoliklarni ko’rishimiz mumkin. Lekin agar skript boshqa manbadan kelsa, unda xatoliklar haqida ko’p ma’lumot bo’lmaydi.
Xuddi shunday cross-origin siyosati (CORS) boshqa turdagi resurslar uchun ham qo’llaniladi.
Cross-origin kirishga ruxsat berish uchun <script> tegi crossorigin atributiga ega bo’lishi va masofaviy server maxsus sarlavhalarni taqdim etishi kerak.
Cross-origin kirishning uch darajasi mavjud:
crossoriginatributi yo’q – kirish taqiqlanган.crossorigin="anonymous"– agar serverAccess-Control-Allow-Originsarlavhasi bilan*yoki bizning manbamiz bilan javob bersa, kirish ruxsat etiladi. Brauzer masofaviy serverga avtorizatsiya ma’lumotlari va cookie’larni jo’natmaydi.crossorigin="use-credentials"– agar server bizning manbamiz bilanAccess-Control-Allow-OriginvaAccess-Control-Allow-Credentials: truesarlavhalarini yuborsa, kirish ruxsat etiladi. Brauzer masofaviy serverga avtorizatsiya ma’lumotlari va cookie’larni jo’natadi.
Cross-origin kirish haqida batafsil ma’lumotni fetch bo’limida o’qishingiz mumkin. U tarmoq so’rovlari uchun fetch usulini tavsiflaydi, lekin siyosat aynan bir xil.
Bizning holatimizda crossorigin atributi yo’q edi. Shuning uchun cross-origin kirish taqiqlangan edi. Keling, uni qo’shamiz.
Biz "anonymous" (cookie’lar jo’natilmaydi, bitta server tomoni sarlavhasi kerak) va "use-credentials" (cookie’lar ham jo’natiladi, ikkita server tomoni sarlavhasi kerak) o’rtasida tanlashimiz mumkin.
Agar cookie’lar bizga muhim bo’lmasa, "anonymous" to’g’ri tanlov:
<script>
window.onerror = function(message, url, line, col, errorObj) {
alert(`${message}\n${url}, ${line}:${col}`);
};
</script>
<script crossorigin="anonymous" src="https://cors.javascript.info/article/onload-onerror/crossorigin/error.js"></script>
Endi server Access-Control-Allow-Origin sarlavhasini taqdim etganini hisobga olsak, hammasi joyida. Bizda to’liq xatolik hisoboti bor.
Xulosa
Rasmlar <img>, tashqi stillar, skriptlar va boshqa resurslar ularning yuklanishini kuzatish uchun load va error hodisalarini taqdim etadi:
loadmuvaffaqiyatli yuklashda ishga tushadi,errormuvaffaqiyatsiz yuklashda ishga tushadi.
Yagona istisno <iframe>: tarixiy sabablarga ko’ra u har doim load ni ishga tushiradi, har qanday yuklash tugashida, hatto sahifa topilmasa ham.
readystatechange hodisasi ham resurslar uchun ishlaydi, lekin kamdan-kam ishlatiladi, chunki load/error hodisalari soddaroq.
Izohlar
<code>yorlig'ini ishlating, bir nechta satrlar uchun - ularni<pre>yorlig'i bilan o'rab qo'ying, 10 satrdan ortiq bo'lsa - sandbox (plnkr, jsbin, codepen…)