前言
在大量网站项目产品中,大多数都存在大量的图片在加载,如首页广告图,菜单栏导航图,产品列表缩略图,产品详情大图等等。大量的图片以及图片体积过大往往会影响页面的加载速度,网站加载速度慢也必然会造成不良的用户体验,最终会造成用户流失等等,而网站快速的加载速度则会让用户有完美的体验。
为什么要进行图片懒加载?
我们先来看一下某网站在页面启动时的情景。
如图所示,这是某网站的首页,页面启动时加载了几十张图片,这些图片请求几乎是并发的,在 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 的步骤:
-
创建观察器实例: 使用
new IntersectionObserver(callback, options)
创建一个观察器实例。callback
是一个回调函数,用于处理交叉状态的变化;options
是观察器的配置参数,可以设置用于判断交叉状态的阈值、根节点等。 -
指定目标元素: 使用观察器实例的
observe(target)
方法,将要观察的目标元素添加进观察器。目标元素可以是单个元素,也可以是一个节点列表。 -
处理交叉状态变化: 当被观察的目标元素与视口发生交叉状态变化时,观察器会执行指定的回调函数。回调函数会接收一个参数,即包含交叉信息的观察器实例数组(一般只有一个实例)。通过这些交叉信息,可以获取目标元素与视口之间的交叉比例、交叉区域的位置等。
-
解除观察: 使用观察器实例的
unobserve(target)
方法,可以取消对特定目标元素的观察。当不再需要观察某个元素或者页面销毁时,应及时解除观察,以避免资源的浪费。
Intersection Observer
API 的优势在于它可以提供更好的性能和效率,减少了手动监听滚动事件并计算元素位置的复杂性。它使用浏览器原生的算法来判断交叉状态,能够在性能友好的情况下,准确、高效地处理元素的可见性变化。
总而言之,Intersection Observe
r 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脚本等。
懒加载和预加载都是通过对资源加载时机进行调整,以提高页面性能和用户体验。懒加载将资源的加载延迟到需要的时候,避免了一次性加载大量资源造成的性能问题;而预加载则是提前加载资源,确保用户在需要时能够快速获取到所需的内容。两者可以结合使用,根据具体场景和需求来选择合适的优化策略。
注:本文不对预加载做过多的讲解
总结
为提高网站加载性能,图片懒加载是必要的;
图片懒加载的核心点包括以下几个方面:
-
监听滚动事件:通过监听用户的滚动事件,判断页面上的图片是否进入了可视区域。一旦图片进入可视区域,就触发加载操作。
-
设置占位符:在页面加载时,可以先为图片设置一个占位符,通常是一个占位图或者是图片的尺寸占位。这样可以保持页面的布局稳定,避免因图片加载导致页面抖动。
-
动态加载图片:当图片进入可视区域时,通过 JavaScript 动态创建 img 元素,并将图片的真实地址赋值给该元素的 src 属性。这会触发浏览器加载图片资源。
-
懒加载优化:为了更好地优化懒加载效果,可以考虑延迟加载图片的时间,即不是在图片完全进入可视区域时立即加载,而是延迟一小段时间,以避免过于频繁地触发加载操作。
-
处理异常和兼容性:在实现图片懒加载时需要注意处理异常情况,比如图片加载失败、图片资源无法访问等情况。此外,考虑到不同浏览器和设备的兼容性,可使用现有的第三方库或框架,以便更方便地实现图片懒加载功能。
通过以上核心点的实施,可以达到优化网页加载性能、减轻服务器负载以及提升用户体验的目的。