Intersection Observer — lazy loading uchun

~15 daq · JavaScript · Brauzer API lari

Muammodan boshlaylik

Sahifada 100 ta rasm bor. Foydalanuvchi hozir faqat birinchi 5 tasini ko'radi — qolgan 95 tasi ekran ostida. Lekin sahifa yuklanayotganda barchasi yuklandi: 100 ta rasmga 100 ta HTTP so'rov ketdi.

Bu muammolar tug'diradi:

  • Sahifa sekin yuklanadi — katta fayllar ko'p
  • Foydalanuvchi hech qachon pastga tushmasligi mumkin — 95 ta rasm behuda yuklandi
  • Mobil internetda — trafik sarflanadi

Yechim — lazy loading: rasm ekranga ko'rinib qolganida yuklansin, oldin emas.

Buni qanday qilish mumkin? Eski usul — scroll hodisasini tinglash, har scrollda rasmlar pozitsiyasini hisoblash. Bu juda sekin va brauzer yuklanadi.

Intersection Observer — zamonaviy va samarali yechim.


Intersection Observer nima?

Intersection Observer — brauzerga "mana bu element ko'rinib qolsa menga ayt" deb buyurish usuli. Brauzer o'zi kuzatadi — siz hisoblashmaysiz.

Hayotiy o'xshatma

Ko'cha devoriga reklama taxtasi o'rnatilgan. Reklama beruvchi bilmoqchi: "qancha odam bu taxtani ko'rdi?" Eski usul — odamlarni sanash uchun biror joyda turib hisoblash. Yangi usul — sensor o'rnatish: odam yaqinlashganda sensor o'zi signal beradi, reklama beruvchi biladi.

Intersection Observer — o'sha sensor. Siz o'rnatib qo'yasiz, brauzer o'zi kuzatadi.


Asosiy ishlatilish

const kuzatuvchi = new IntersectionObserver(function(yozuvlar) {
  yozuvlar.forEach(function(yozuv) {
    if (yozuv.isIntersecting) {
      // ← element ko'rindi
      console.log("Ko'rindi:", yozuv.target);
    }
  });
});

const element = document.querySelector(".kuzatiladigan");
kuzatuvchi.observe(element); // ← kuzatishni boshlash

isIntersecting — element viewport da ko'rinadimi? true — ko'rinyapti.


Lazy loading — amaliy misol

HTML da rasmlar avval yuklanmaydi — data-src atributiga manzil yoziladi, src bo'sh qoladi:

<img data-src="/rasmlar/tog.jpg"    alt="Tog'" class="lazy-rasm">
<img data-src="/rasmlar/daryo.jpg"  alt="Daryo" class="lazy-rasm">
<img data-src="/rasmlar/sahro.jpg"  alt="Sahro" class="lazy-rasm">

JavaScript — rasm ko'ringanda haqiqiy src ga o'tkazadi:

const kuzatuvchi = new IntersectionObserver(function(yozuvlar) {
  yozuvlar.forEach(function(yozuv) {
    if (!yozuv.isIntersecting) return; // ← ko'rinmayotgan bo'lsa — e'tiborsiz

    const rasm = yozuv.target;
    rasm.src = rasm.dataset.src; // ← haqiqiy src qo'yildi — brauzer yuklaydi

    kuzatuvchi.unobserve(rasm); // ← rasm yuklandi, endi kuzatish shart emas
  });
});

// Barcha lazy rasmlarni kuzatishga qo'shish
document.querySelectorAll(".lazy-rasm").forEach(function(rasm) {
  kuzatuvchi.observe(rasm);
});

Nima uchun unobserve kerak?

Rasm bir marta yuklandidan keyin uni kuzatishda davom etish shart emas. unobserve — kuzatuvchidan olib tashlash. Bu resurslarni tejaydi.


rootMargin — oldindan yuklash

Foydalanuvchi pastga tushayotganda — rasm ko'rinib qolguncha kutish kerak emas. Biroz oldinroq — "ekranga 200px qolganida" yuklanishni boshlash yanada qulay.

const kuzatuvchi = new IntersectionObserver(
  function(yozuvlar) {
    yozuvlar.forEach(function(yozuv) {
      if (!yozuv.isIntersecting) return;
      yozuv.target.src = yozuv.target.dataset.src;
      kuzatuvchi.unobserve(yozuv.target);
    });
  },
  {
    rootMargin: "200px", // ← element ko'rinishdan 200px oldin signal
  }
);

Foydalanuvchi hali etib kelmagan — rasm esa allaqachon yuklanib bo'ldi. Ko'zgacha uzluksiz ko'rinish.


threshold — qancha ko'ringanda

threshold — elementning qancha qismi ko'ringanda signal berish. 0 dan 1 gacha.

const kuzatuvchi = new IntersectionObserver(
  function(yozuvlar) { ... },
  {
    threshold: 0.5, // ← element 50% ko'ringanda signal
  }
);
threshold: 0    // ← bir piksel ko'ringanda (standart)
threshold: 0.5  // ← yarmidan ko'pi ko'ringanda
threshold: 1    // ← to'liq ko'ringanda
threshold: [0, 0.25, 0.5, 0.75, 1] // ← har bir chegarada signal

"Infinity scroll" — pastga tushganda yangi ma'lumot

Lazy loading dan tashqari, Intersection Observer "infinity scroll" uchun ham ishlatiladi. Ro'yxat oxiriga kelganda yangi ma'lumot yuklanadi.

const yuklovchi = document.getElementById("yuklovchi"); // ro'yxat oxiridagi element

const kuzatuvchi = new IntersectionObserver(async function(yozuvlar) {
  if (!yozuvlar[0].isIntersecting) return;

  kuzatuvchi.unobserve(yuklovchi); // ← kuzatishni to'xtatib

  const yangilar = await keyingiSahifaOl(); // ← yangi ma'lumot olish
  ro_yxatgaQosh(yangilar);

  kuzatuvchi.observe(yuklovchi); // ← yana kuzatishni boshlash
});

kuzatuvchi.observe(yuklovchi);

Tez-tez uchraydigan xatolar

Yuklanib bo'lgan rasmni qayta yuklashga urinish:

// ❌ — src allaqachon to'g'ri, lekin unobserve unutildi
// Observer qayta ishlaydi, src qayta o'rnatiladi
kuzatuvchi.observe(rasm);

// ✅ — yuklangandan keyin unobserve
if (!yozuv.isIntersecting) return;
rasm.src = rasm.dataset.src;
kuzatuvchi.unobserve(rasm); // ← muhim

Rasm yuklanmay qolishi — data-src yo'q:

// ❌ — data-src atributi yo'q
const rasm = document.createElement("img");
rasm.alt = "Rasm";
// data-src qo'yilmadi

// ✅
rasm.dataset.src = "/rasmlar/manzara.jpg";
rasm.alt = "Manzara";

Xulosa

Intersection Observer — element viewport da ko'rinyaptimi kuzatuvchi. scroll hodisasidan tez va qulay.

Lazy loading — rasm ko'ringanda yuklash. data-src → src o'tkazish. Yuklanganida unobserve.

rootMargin — element ko'rinishdan N px oldin signal. Oldindan yuklash uchun.

threshold — elementning qancha qismi ko'ringanda signal berish.


Keyingi dars

53-dars: MutationObserver — DOM o'zgarishlarini kuzatish