Hujjat va resurs yuklanishi

Resurs yuklash: onload va onerror

Brauzer bizga tashqi resurslar โ€” skriptlar, rasm, iframe va boshqalar โ€” yuklanishini kuzatish imkonini beradi. Buning uchun ikkita asosiy hodisa bor: load โ€” resurs muvaffaqiyatli yuklandi va error โ€” yuklashda xatolik yuz berdi. Bu, masalan, skriptni dinamik yuklab, u tayyor bo'lgach undagi funksiyalarni chaqirish uchun, yoki rasm yuklanmaganda zaxira rasmni ko'rsatish uchun kerak bo'ladi. Ushbu darsda resurs yuklanishini kuzatishni chuqur o'rganamiz.

Bu darsdagi misollar brauzer muhitiga (DOM elementlari, document) tegishli. Kurs maydonchasi Node.js muhitida ishlaydi va DOM'ga ega emas โ€” shu sabab misollar statik, faqat o'qish uchun keltiriladi.

load va error hodisalari

Ko'pchilik resurslar, ya'ni tashqi srcga ega elementlar (rasm, tashqi skript va h.k.) ikkita hodisani generatsiya qiladi:

Istisno: <iframe> โ€” u tarixiy sabablarga ko'ra yuklash tugagach har doim loadni generatsiya qiladi, hatto sahifa topilmasa ham.

Skriptni yuklashni kuzatish (script.onload)

Aytaylik, biz tashqi skriptdagi funksiyani chaqirmoqchimiz. Skriptni dinamik yuklaymiz:

let script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js';
document.head.append(script);

Lekin skript yuklanguncha undagi funksiyalarni chaqira olmaymiz. Skript qachon tayyor bo'lishini bilish uchun load hodisasidan foydalanamiz:

let script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js';
document.head.append(script);

script.onload = function() {
  // skript yuklandi, endi undagi o'zgaruvchi va funksiyalar mavjud
  alert(_.VERSION); // lodash kutubxonasi versiyasi
};

onload ishlovchisi skript yuklanib, bajarilib bo'lgach ishga tushadi. Shu paytda skript e'lon qilgan barcha o'zgaruvchi va funksiyalardan foydalanish mumkin.

script.onerror

Skriptni yuklashda xatoliklarni ham kuzatishimiz kerak. error hodisasi yuklash muvaffaqiyatsiz bo'lganda ishga tushadi:

let script = document.createElement('script');
script.src = 'https://example.com/mavjud-emas.js'; // bunday skript yo'q
document.head.append(script);

script.onerror = function() {
  alert('Xatolik: ' + this.src + ' yuklanmadi');
};

Bu yerda mavjud bo'lmagan skript yuklanishga urinilgani uchun onerror ishga tushadi.

Muhim: onload/onerror faqat yuklash jarayonining o'zini kuzatadi โ€” resurs olindimi yoki yo'qmi. Agar skript yuklandi, lekin uning ichida xatolik bo'lsa (masalan, kod ichida throw yoki sintaksis xatosi), buni onerror ushlamaydi. Yuklash muvaffaqiyatli bo'lgani uchun onload baribir ishga tushadi. Kod ichidagi xatoliklarni kuzatish uchun window.onerror global ishlovchisidan foydalaniladi.

Boshqa resurslar (rasm, iframe)

load va error hodisalari boshqa resurslar uchun ham ishlaydi, ba'zi nozikliklar bilan.

Rasmlar (<img>), tashqi stillar, skriptlar va boshqa resurslarda onload va onerror hodisalari mavjud:

let img = document.createElement('img');
img.src = 'https://js.cx/clipart/train.gif'; // yuklashni boshlaydi

img.onload = function() {
  alert(`Rasm yuklandi, o'lchami: ${img.width}x${img.height}`);
};

img.onerror = function() {
  alert('Rasm yuklashda xatolik');
};

Rasm uchun ba'zi nozikliklar bor: aksariyat brauzerlarda rasmni yuklash src tayinlangan zahoti boshlanadi (elementni documentga qo'shish shart emas). Shu sabab onloadni srcdan oldin tayinlash yaxshi amaliyot โ€” aks holda keshdagi rasm darhol yuklanib, hodisani "o'tkazib yuborish" ehtimoli bor:

let img = document.createElement('img');

// avval hodisa ishlovchilarini tayinlaymiz
img.onload = () => alert('Yuklandi');
img.onerror = () => alert('Xatolik');

// keyin src โ€” shu paytda yuklash boshlanadi
img.src = 'https://js.cx/clipart/train.gif';
<iframe> uchun load hodisasi iframe ichidagi sahifa yuklanib bo'lgach ishlaydi โ€” muvaffaqiyatli ham, muvaffaqiyatsiz ham (masalan, 404). Bu tarixiy xususiyat, shuning uchun iframe'da error hodisasiga ishonib bo'lmaydi.

Crossorigin siyosati (crossorigin atributi)

Bir muhim qoida bor: bir saytdagi (origin) skript boshqa saytning ichki ma'lumotlariga kira olmaydi. Aniqrog'i, bitta origin (domen/port/protokol) boshqasidagi resurs tarkibiga to'liq kira olmaydi. Bu "Same-Origin Policy" (bir manba siyosati) deb ataladi va xavfsizlik uchun mavjud.

Agar boshqa domendan (masalan, CDN'dan) yuklangan skriptda xatolik yuz bersa, window.onerror global ishlovchisi bu haqda batafsil ma'lumot ololmaydi โ€” u faqat qisqa "Script error" xabarini oladi, satr raqami yoki xato tafsilotlarisiz. Bu xavfsizlik cheklovi.

Buning sababi โ€” skript boshqa domendan bo'lsa, uning ichki xatolik ma'lumotini ko'rsatish maxfiy ma'lumotning sizib chiqishiga olib kelishi mumkin. Masalan, boshqa domendagi skript ichida foydalanuvchiga xos ma'lumot bo'lsa, xato xabari orqali uni o'g'irlash mumkin bo'lardi.

To'liq xatolik ma'lumotini olish uchun ikki narsa kerak:

  1. Tashqi skriptda crossorigin atributi bo'lishi;
  2. Uzoq server esa Access-Control-Allow-Origin HTTP sarlavhasini yuborishi.

crossorigin atributining uch varianti bor:

<script crossorigin="anonymous" src="https://another-site.com/script.js"></script>
Aksariyat hollarda uchinchi tomon skriptlari uchun crossorigin="anonymous" yetarli. Bu esa window.onerrorda to'liq xato tafsilotlarini olish imkonini beradi โ€” bu, ayniqsa, ishlab chiqarishda (production) xatolarni kuzatuvchi tizimlar (Sentry va h.k.) uchun muhim.

Resurs holatini kuzatish (amaliy misol)

Yuqoridagi bilimlarni birlashtirib, resursni yuklab, uni kuzatuvchi umumiy funksiya yozamiz. Bu funksiya skriptni yuklaydi va callback orqali natijani (xato yoki muvaffaqiyat) qaytaradi:

function loadScript(src, callback) {
  let script = document.createElement('script');
  script.src = src;
  document.head.append(script);

  script.onload = () => callback(null, script);
  script.onerror = () => callback(new Error('Skript yuklashda xatolik: ' + src));
}

// ishlatish:
loadScript('https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js', function(error, script) {
  if (error) {
    // xatolikni qayta ishlash
    alert(error.message);
  } else {
    // skript muvaffaqiyatli yuklandi
    alert('Yuklandi: ' + script.src);
  }
});

Bu Node.js uslubidagi (error-first) callback pattern โ€” birinchi argument xato, ikkinchisi natija. Uni Promise'ga o'rab, async/await bilan ishlatish ham mumkin:

function loadScriptPromise(src) {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script');
    script.src = src;
    document.head.append(script);

    script.onload = () => resolve(script);
    script.onerror = () => reject(new Error('Xatolik: ' + src));
  });
}

// ishlatish:
loadScriptPromise('https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js')
  .then(script => alert('Yuklandi'))
  .catch(error => alert(error.message));
Bir necha resursni ketma-ket yoki parallel yuklashda Promise varianti juda qulay: Promise.all bilan hammasini parallel yuklab, hammasi tayyor bo'lishini kutish mumkin.

Xulosa

Tashqi resurslarni yuklashni kuzatish:

Crossorigin (bir manba) siyosati: boshqa domendan yuklangan skript xatoliklarining to'liq ma'lumotini olish uchun crossorigin atributi va server tomonida Access-Control-Allow-Origin sarlavhasi kerak. crossorigin="anonymous" odatda yetarli.

Amaliyotda resurs yuklashni kuzatish ko'p ishlatiladi: dinamik skript va stillarni yuklash, rasm yuklanmaganda zaxira ko'rsatish, ko'p resurslarni Promise.all bilan boshqarish. Bu texnikalar zamonaviy SPA (Single Page Application) ilovalarida asos hisoblanadi.