Intersection Observer báo bất đồng bộ khi một element vào/ra khỏi viewport (hoặc khỏi một container), thay cho việc nghe scroll rồi gọi getBoundingClientRect() liên tục.
js
const io = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) continue
entry.target.src = entry.target.dataset.src // lazy load
io.unobserve(entry.target) // xong thì bỏ theo dõi
}
}, {
root: null, // null = viewport
rootMargin: '200px', // kích hoạt sớm 200px trước khi lọt vào màn hình
threshold: 0.25, // 25% element hiện ra thì tính là intersecting
})
document.querySelectorAll('img[data-src]').forEach((el) => io.observe(el))Vì sao hơn scroll listener: callback chạy ngoài luồng cuộn, browser tự gộp nhiều element, không gây layout thrashing do đọc getBoundingClientRect() mỗi frame.
Dùng cho: lazy load ảnh/iframe, infinite scroll, kích hoạt animation khi cuộn tới, đo tỉ lệ hiển thị quảng cáo.
Lưu ý: callback luôn chạy một lần ngay khi observe() để báo trạng thái ban đầu — nếu không kiểm tra isIntersecting sẽ tưởng element vừa cuộn tới.