Nhớ lại xem, đã bao giờ bạn hì hục code một trang landing page dài ngoằng, nhét đầy ảnh chất lượng cao và rồi khóc thét vì web load chậm như rùa bò? Hoặc tệ hơn, bạn dùng sự kiện cuộn chuột (scroll) để làm hiệu ứng hiện chữ, khiến trình duyệt giật tung chảo? Đó là lúc bạn cần biết đến Intersection Observer – một "đặc vụ ngầm" giúp website của bạn nhẹ tênh và tối ưu hiệu năng tuyệt đối.
Nỗi ám ảnh mang tên sự kiện "onScroll"
Trước đây, để biết một phần tử đã xuất hiện trên màn hình hay chưa, lập trình viên thường gắn window.addEventListener('scroll'). Nhưng ngặt nỗi, mỗi lần người dùng lăn chuột nhích một pixel, hàm của bạn sẽ bị gọi hàng chục lần. Trình duyệt phải liên tục tính toán tọa độ để kiểm tra vị trí.

Quá trình này ngốn rất nhiều tài nguyên, làm tụt FPS thê thảm khiến người dùng có cảm giác trang web bị đơ. Dù bạn có dùng tuyệt chiêu từ bài Cách Debounce & Throttle giúp website mượt mà, thì nó vẫn chưa phải là cách xịn nhất cho bài toán này. Bạn cần một cơ chế chủ động và thông minh hơn.
Intersection Observer là gì mà "thần thánh" vậy?
Thay vì cứ một mili-giây lại đi hỏi trình duyệt "Ê, cái ảnh này hiện lên chưa?", Intersection Observer hoạt động theo cơ chế "báo thức". Bạn chỉ việc đăng ký phần tử cần theo dõi, trình duyệt sẽ tự động "gọi" bạn ngay khoảnh khắc phần tử đó lấp ló trên màn hình.
- Giải phóng luồng chính: Mọi tính toán diễn ra ở background, không làm treo JavaScript.
- Code gọn gàng: Không cần hì hục dùng
getBoundingClientRect()rườm rà. - Hiệu năng tăng vọt: Giúp điểm UXUI Performance xanh mướt trên các công cụ đo lường.
Việc áp dụng nó sẽ thay đổi hoàn toàn cách bạn tư duy về DOM.
Thực hành ngay: Viết Lazy Load cho ảnh
Hãy xem cách chúng ta giải quyết bài toán tải hàng trăm bức ảnh. Thay vì bắt người dùng tải hết một lần, ta chỉ tải ảnh khi họ cuộn tới đó.
const lazyImages = document.querySelectorAll('.lazy-img');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // Tráo link ảnh thật vào
observer.unobserve(img); // Xong việc thì huỷ theo dõi
}
});
});
lazyImages.forEach(img => observer.observe(img));
Mẹo nhỏ: Luôn nhớ gọi unobserve hoặc disconnect() sau khi hoàn thành mục đích để tránh rò rỉ bộ nhớ (memory leak) nhé!
Nếu bạn tò mò muốn biết trình duyệt tiết kiệm được bao nhiêu dung lượng sau khi dùng đoạn code này, hãy mở ngay tab Network. Đừng quên ôn lại Cách Chrome DevTools giúp bạn soi lỗi UI để tự mình kiểm chứng tốc độ nhé.
Tinh chỉnh thông minh với rootMargin và threshold
Để trải nghiệm mượt hơn, bạn đừng dùng cấu hình mặc định. Hãy thêm tham số rootMargin: "50px" vào Observer. Thuộc tính này giúp bạn "ăn gian", bắt đầu tải ảnh từ khi người dùng còn cách nó 50px. Kết quả là ảnh đã load xong trước cả khi họ kịp nhìn thấy.
Ngoài ra, threshold: 0.5 sẽ chỉ kích hoạt hiệu ứng khi phần tử đã lộ diện được đúng một nửa. Để đào sâu hơn vào các mánh khóe này, tài liệu Intersection Observer API trên MDN là nơi bạn bắt buộc phải đọc qua. Và tất nhiên, nếu bạn muốn rèn giũa kỹ năng từ gốc rễ, luôn có những lộ trình bài bản chờ bạn tại DIA DEMY.
Giờ thì bạn đã có trong tay vũ khí để xóa sổ tình trạng web giật lag vì ngập ngụa hình ảnh. Nhưng khoan đã, nếu chúng ta muốn dùng chính Intersection Observer để đo lường chính xác thời gian một người dừng lại đọc một đoạn văn (dwell time) thì logic đằng sau sẽ phải tùy biến như thế nào? Bật mí nhé, nó không dễ ăn như làm lazy loading đâu!




Vui lòng đăng nhập để bình luận.