likes
comments
collection
share

分分钟让你实现图片懒加载,提高用户体验浏览器解析HTML文档并构建DOM树时,会遇到`<img>`标签,这通常触发图片资

作者站长头像
站长
· 阅读数 24

图片懒加载(Lazy Loading)是一种常见的前端性能优化技术,用于改善用户体验和页面加载速度。当用户浏览网页时,并非所有图片都需要立即加载到内存中,特别是那些位于屏幕下方、尚未进入可视区域的图片。通过懒加载,我们只在需要的时候加载图片,从而减少初始页面加载时间,节省带宽资源,提升网站性能。

一、浏览器的工作机制与懒加载的必要性

浏览器解析HTML文档并构建DOM树时,会遇到<img>标签,这通常触发图片资源的立即下载。然而,在现代Web应用中,一般的网页都含多图,如电商网站商品展示,会显著增加服务器负担,拖慢页面渲染速度并消耗额外带宽。以单张1MB图片为例,在10000用户并发访问场景下,瞬时带宽需求可达10GB,对网络资源造成巨大压力。因此,网站需采用优化策略,如图片压缩、懒加载等技术,以提升用户体验和减轻服务器负载。

实现懒加载的基本步骤

  1. 修改图片源引用: 将<img>标签中的src属性替换为data-src,后者存储实际的图片URL。浏览器不会解析data-前缀的属性来下载资源,这样图片就不会在页面加载初期被加载。
  2. 监听滚动事件: 使用JavaScript监听窗口的scroll事件,检查哪些图片进入了可视区域。一旦图片进入可视区域,就将data-src的值赋给src,触发图片的实际下载和显示。
  3. 性能考虑: 为了避免频繁触发scroll事件导致的性能问题,可以通过requestAnimationFrame或节流函数(throttle function)来限制事件处理函数的执行频率,确保即使在快速滚动时也能保持良好的性能。

二、深入理解懒加载的关键点

  • 浏览器的多线程机制: 尽管JS是单线程的,但浏览器在处理资源下载时使用了多线程。这意味着图片、CSS和JS文件等资源可以同时下载,提高加载效率。但是,过多的并发下载可能受到网络限制,如TCP/IP连接的数量限制,因此合理控制并发数是必要的。
  • DOM操作与性能: 在实现懒加载时,频繁地修改DOM可能会导致重绘和重排,影响性能。因此,应当尽量减少DOM操作,例如在每次滚动后批量更新图片源,而不是逐个处理。
  • 数据属性与datasetdata-属性是HTML5引入的一个特性,用于存储页面或应用程序的私有自定义数据。通过dataset属性,可以方便地访问这些数据属性,例如element.dataset.src获取data-src的值。

三、实现方式详解

图片懒加载的实现方法多样,下面介绍三种主流的实现方式。

1. 基础懒加载

HTML5引入了loading="lazy"属性,使得懒加载的实现变得简单。只需在<img>标签中添加该属性,浏览器便会在图片接近可视区域时自动加载。

<img src="placeholder.jpg" data-src="image-to-lazy-load.jpg" loading="lazy" alt="Lazy Loaded Image">

这里的src属性放置一个占位符图片,而实际要加载的图片路径存储在data-src中。这种方案适合于不需要高度定制化的场景。

2. 使用Intersection Observer API

对于需要更精细控制的场景,Intersection Observer API提供了强大的能力。通过监听DOM元素与视口的交集变化,就可以决定何时加载图片。

<!-- HTML 结构 -->
<img class="lazy" data-src="image-to-lazy-load.jpg" alt="Lazy Loaded Image">

<!-- JavaScript 代码 -->
<script>
  document.addEventListener("DOMContentLoaded", function() {
    var lazyImages = document.querySelectorAll(".lazy");
    var observer = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          var lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          observer.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      observer.observe(lazyImage);
    });
  });
</script>

上面通过创建了一个观察器,当图片与视口发生交集时,会触发图片的真实加载。此方法适用于需要复杂逻辑判断的页面。

3 使用lodash的节流函数来限制loadImage函数的调用频率来延迟加载图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./common.css">
    <!-- 引入lodash库,用于节流函数 -->
    <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
</head>
<body>
    <!-- 图片列表,data-src属性存储真实的图片URL -->
    <img data-price="20" data-src="https://img.36krcdn.com/20190808/v2_1565254363234_img_jpg">
    <img data-src="https://img.36krcdn.com/20190905/v2_1567641293753_img_png">
    <img data-src="https://img.36krcdn.com/20190905/v2_1567640518658_img_png">
    <!-- 更多图片... -->

    <!-- 脚本 -->
    <script>
        // 获取所有图片元素
        const imgs = document.getElementsByTagName('img');
        const num = imgs.length; // 图片总数
        let n = 0; // 已加载图片计数器

        // 页面加载完成时触发
        document.addEventListener('DOMContentLoaded', () => {
            loadImage();
        });

        // 图片加载函数
        function loadImage() {
            // 获取屏幕高度和滚动位置
            let screenHeight = document.documentElement.clientHeight;
            let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

            // 遍历所有图片,判断是否需要加载
            for (let i = 0; i < num; i++) {
                if (imgs[i].offsetTop < screenHeight + scrollTop) {
                    // 如果图片在可视区域内,则加载图片
                    imgs[i].src = imgs[i].getAttribute('data-src');
                    n = i + 1;
                    if (n === num) {
                        // 所有图片加载完成后,移除滚动监听
                        window.removeEventListener('scroll', throttleLayLoad);
                    }
                }
            }
        }

        // 使用lodash的节流函数限制loadImage的调用频率
        const throttleLayLoad = _.throttle(loadImage, 300);
        // 监听滚动事件,触发节流后的图片加载函数
        window.document.addEventListener('scroll', throttleLayLoad);
    </script>
</body>
</html> 

四、核心价值

图片懒加载的核心价值在于优化页面加载效率,主要体现在以下几个方面:

  1. 减少初始加载时间:页面不再一次性加载所有图片,而是按需加载,显著缩短了用户等待的时间。
  2. 节省带宽与服务器资源:通过仅加载可视区域的图片,大幅降低了带宽消耗和服务器的处理负担。
  3. 提升用户体验:在用户滚动页面时动态加载图片,确保了流畅的浏览体验,尤其是在移动设备上表现更为突出。

五、业务逻辑优化与前端实践的技术

  • 预加载与预渲染: 对于即将进入可视区域的图片,可以提前进行预加载,以减少等待时间。预加载通常发生在用户滚动接近图片时,这样可以无缝地展示图片,提升用户体验。
  • 使用Intersection Observer API: 这是一个现代的API,提供了更高效的方式来检测元素是否在视口内,替代了传统的滚动事件监听。它允许开发者注册回调函数,当目标元素进入或离开视口时,自动触发回调,无需手动管理事件监听器。
  • 减少事件处理器的触发次数: 使用节流(throttle)函数,避免在短时间内频繁执行同一段代码。这有助于减少不必要的计算和DOM操作,提升页面响应速度。
转载自:https://juejin.cn/post/7389650655427788810
评论
请登录