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

前言

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

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

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

如图所示,这是某网站的首页,页面启动时加载了几十张图片,这些图片请求几乎是并发的,在 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. 处理异常和兼容性:在实现图片懒加载时需要注意处理异常情况,比如图片加载失败、图片资源无法访问等情况。此外,考虑到不同浏览器和设备的兼容性,可使用现有的第三方库或框架,以便更方便地实现图片懒加载功能。

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

相关推荐
秦jh_7 分钟前
【Linux】多线程(概念,控制)
linux·运维·前端
蜗牛快跑21320 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy21 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与2 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun2 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇2 小时前
ES6进阶知识一
前端·ecmascript·es6
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss