前端性能优化 | 图片懒加载

前言

在大量网站项目产品中,大多数都存在大量的图片在加载,如首页广告图,菜单栏导航图,产品列表缩略图,产品详情大图等等。大量的图片以及图片体积过大往往会影响页面的加载速度,网站加载速度慢也必然会造成不良的用户体验,最终会造成用户流失等等,而网站快速的加载速度则会让用户有完美的体验。

为什么要进行图片懒加载?

我们先来看一下某网站在页面启动时的情景。

如图所示,这是某网站的首页,页面启动时加载了几十张图片,这些图片请求几乎是并发的,在 Chrome 浏览器,最多支持的并发请求次数是有限的,其他的请求会推入到队列中等待或者停滞不前,直到请求完成后新的请求才会发出。所以相当一部分图片资源请求是需要排队等待时间的。 在上面可以看出,图片的大小在几KB 至几MB之间,图片的过大直接导致了加载时间过长,如果需要一个快速的浏览体验,因此图片的加载优化势在必行

优势: 懒加载的优势就在于提高网站的性能。懒加载可以减少页面需要加载的资源数目,从而减少页面的整体大小。这样相当于减少了页面的加载时间,从而提高了用户的体验。其次,懒加载可以降低网站的带宽消耗,特别是对于移动设备等网络环境比较差的情况下,非常有利。懒加载可以降低服务器的负载,提高网站的可靠性。

本文主要从以下几个方面来讲解

一、懒加载的概念

二、图片懒加载的原理

三、图片懒加载的实现方案

四、懒加载和预加载的区别

一、初识懒加载

1、懒加载的概念

概念: 懒加载(Lazy loading),也被称为延迟加载,是一种优化网页性能的技术。它是指在网页加载过程中,将页面中的某些资源(如图片、视频、音频等)推迟加载,只有当用户需要访问到这些资源时才去加载。这样可以减少页面的初始加载时间,提高用户体验。

原理: 懒加载的原理是通过监听用户的浏览行为,当用户滚动到可视区域内时,再进行资源的加载。这样可以避免一次性加载过多的资源,从而减少页面的加载时间和带宽消耗。

主要使用场景: 懒加载适用于图片较多,页面列表较长(长列表)的场景中。

2、懒加载的优点

  • 减少首页加载时间:初始页面只加载必要的内容,而不需要等待所有资源都加载完成。
  • 提高用户体验:页面加载更快,用户可以更快地交互和浏览内容。
  • 节约带宽消耗:只加载用户需要的内容,减少不必要的带宽消耗。

需要注意的是,懒加载并非适用于所有场景。对于一些重要的资源(如主要内容、重要的功能组件等),应当优先加载,以确保用户能够尽快访问到核心内容。而对于一些非必要资源(如底部的图片、辅助功能组件等),可以采用懒加载的方式。

二、图片懒加载的实现原理

1、图片懒加载的概念

图片懒加载是一种常见的网页性能优化技术,它可以延迟加载页面中的图片,只在用户需要时才加载显示,而不是一次性加载所有的图片资源。这可以减少初始页面的加载时间和带宽占用,提升用户的浏览体验。

2、图片懒加载的实现原理

图片懒加载的实现原理通常是通过 JavaScript 监听页面的滚动事件,当用户滚动到特定位置时,判断图片是否进入了可视区域。如果图片进入了可区域,则动态创建 img 元素并将图片资源的地址赋值给 img 元素的 src 属性,触发浏览器加载图片。这样可以减少初始页面的加载时间和带宽占用。

从图中我们还可以看出,图片懒加载的实现原理的核心主要有两个

  • 1、判断图片是否已经进入可视区域范围内
  • 2、图片进入可视区域后触发加载图片

因此解决上述两个核心点也就实现了图片的懒加载,那么如何解决上述两个问题呢?

三、图片懒加载的实现方案

围绕上述引出的问题,实现图片懒加载也就是解决两个核心点

问题一:如何判断图片是否已经进入可视区域范围内?

方案一:获取元素的相对浏览器可是区域的位置:getBoundingClientRect()

这个方案首先需要获取两个高度:浏览器窗口高度(可视区域高度)和元素距离浏览器窗口顶部的高度

(1)获取浏览器窗口高度(可视区域高度)

浏览器窗口高度通过 document.documentElement.clientHeight 这个 API 来获取,如下图所示浏览器常用高度的示意图,从图中,很清晰的可以看到clientHeight的高度

(2)获取元素距离浏览器窗口顶部的高度

获取元素距离可视区域顶部的高度需要通过getBoundingClientRect() API 来实现,getBoundingClientRect() 获取的是 DOM 元素相对于窗口的坐标集合,集合中有多个属性,其中的 top 属性就是当前元素元素距离窗口可视区域顶部的距离,如下图所示

通过这两个高度判断的方法,实现方案也就有了,通过监听并计算 当前可视区域的高度 - 元素距离可视区域顶部的高度 ,当这个高度差小于 0 时说明图片已经进入可视区域,这时开始加载图片。

js 复制代码
// 获取所有图片标签
const imgs = document.getElementsByTagName("img");
// 获取可视区域的高度
const viewHight = document.documentElement.clientHeight;
// 统计当前加载到了哪张照片,避免每一次都从第一张照片开始检查
let num = 0;

function lazyload() {
  for (let i = num; i < imgs.length; i++) {
    const item = imgs[i]
    // 可视区域高度减去元素顶部距离可视区域顶部的高度,如果差值大于 0 说明元素展示
    let distance = viewHight - item.getBoundingClientRect().top;
    if (distance >= 0) {
      // 展示真实图片
	    item.src = item.getAttribute("data-src");
      num = i + 1;
    }
  }
}

// 监听 scroll 事件,实际项目中需要进行节流优化
window.addEventListener("scroll", lazyload, false);

lazyload();

方案二:异步观察目标元素:Intersection Observer

Intersection Observer(交叉观察器)是一个现代的 JavaScript API,用于监测页面上元素与视口(可见区域)之间的交叉状态。它可以轻松地实现一些与元素可见性相关的功能,如图片懒加载、无限滚动、响应式布局等。

Intersection Observer API 的核心概念是观察器(Observer)和目标元素(Target)。观察器用于监听目标元素与视口之间的交叉信息,并在交叉状态发生变化时执行相应的回调函数。

使用 Intersection Observer API 的步骤:

  1. 创建观察器实例: 使用 new IntersectionObserver(callback, options) 创建一个观察器实例。callback 是一个回调函数,用于处理交叉状态的变化;options 是观察器的配置参数,可以设置用于判断交叉状态的阈值、根节点等。

  2. 指定目标元素: 使用观察器实例的 observe(target) 方法,将要观察的目标元素添加进观察器。目标元素可以是单个元素,也可以是一个节点列表。

  3. 处理交叉状态变化: 当被观察的目标元素与视口发生交叉状态变化时,观察器会执行指定的回调函数。回调函数会接收一个参数,即包含交叉信息的观察器实例数组(一般只有一个实例)。通过这些交叉信息,可以获取目标元素与视口之间的交叉比例、交叉区域的位置等。

  4. 解除观察: 使用观察器实例的 unobserve(target) 方法,可以取消对特定目标元素的观察。当不再需要观察某个元素或者页面销毁时,应及时解除观察,以避免资源的浪费。

Intersection Observer API 的优势在于它可以提供更好的性能和效率,减少了手动监听滚动事件并计算元素位置的复杂性。它使用浏览器原生的算法来判断交叉状态,能够在性能友好的情况下,准确、高效地处理元素的可见性变化。

总而言之,Intersection Observer API 可以简化元素可见性的监测工作,让开发者可以更方便地实现一些与元素可见性相关的功能,提升用户体验。

js 复制代码
const io = new IntersectionObserver((entries) => {
  entries.forEach(item => {
    // 当前元素可见时
    if(item.isIntersecting) {
      item.target.src = item.target.dataset.src // 替换 src
      io.unobserve(item.target) // 停止观察当前元素,避免不可见时再次调用 callback 函数
    }
  })
})

const imgs = document.querySelectorAll('[data-src]')

// 监听所有图片元素
imgs.forEach(item => {
  io.observe(item)
})

问题二:图片进入可视区域后触发加载图片

对于这个问题,实现思路也很简单,需要用到 DOM 元素的 dataset 属性,所有以 data- 开头的属性都可以用做自定义属性,所以我们可以定义一个 data-src 属性存放需要加载的图片链接,src 属性使用 loading 占位图片,当需要加载图片的时候,把 src 的链接更换为 data-src 的链接即可

js 复制代码
<img data-src="需要加载的图片链接" src="图片占位loading图片地址">

四、懒加载和预加载

懒加载和预加载是两种优化网页性能的技术,它们在资源加载的时机和方式上有所不同。

这两种方式都是提高网页性能的方式,两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

懒加载(Lazy loading)是将某些资源在需要时再进行加载。在网页加载过程中,只加载当前可视区域内的内容,当用户滚动页面或者进行特定操作时,再加载进入视野的内容。这可以减少初始页面的加载时间,提高用户体验。懒加载常用于图片等大型文件的加载,帮助减少页面的加载压力。

预加载(Preloading)则是在网页加载时提前加载将来会用到的资源。通过在网页中声明关键资源,浏览器会在页面加载完成后开始提前加载这些资源,即使用户尚未进行相关操作。这样可以在用户需要时即可获取到已经加载好的资源,提高访问速度和响应时间。预加载常用于网页中的重要组件、CSS样式文件、JavaScript脚本等。

懒加载和预加载都是通过对资源加载时机进行调整,以提高页面性能和用户体验。懒加载将资源的加载延迟到需要的时候,避免了一次性加载大量资源造成的性能问题;而预加载则是提前加载资源,确保用户在需要时能够快速获取到所需的内容。两者可以结合使用,根据具体场景和需求来选择合适的优化策略。

注:本文不对预加载做过多的讲解

总结

为提高网站加载性能,图片懒加载是必要的;

图片懒加载的核心点包括以下几个方面:

  1. 监听滚动事件:通过监听用户的滚动事件,判断页面上的图片是否进入了可视区域。一旦图片进入可视区域,就触发加载操作。

  2. 设置占位符:在页面加载时,可以先为图片设置一个占位符,通常是一个占位图或者是图片的尺寸占位。这样可以保持页面的布局稳定,避免因图片加载导致页面抖动。

  3. 动态加载图片:当图片进入可视区域时,通过 JavaScript 动态创建 img 元素,并将图片的真实地址赋值给该元素的 src 属性。这会触发浏览器加载图片资源。

  4. 懒加载优化:为了更好地优化懒加载效果,可以考虑延迟加载图片的时间,即不是在图片完全进入可视区域时立即加载,而是延迟一小段时间,以避免过于频繁地触发加载操作。

  5. 处理异常和兼容性:在实现图片懒加载时需要注意处理异常情况,比如图片加载失败、图片资源无法访问等情况。此外,考虑到不同浏览器和设备的兼容性,可使用现有的第三方库或框架,以便更方便地实现图片懒加载功能。

通过以上核心点的实施,可以达到优化网页加载性能、减轻服务器负载以及提升用户体验的目的。

相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax