前言
最近在学习中确实收获了挺多东西,其中我觉得有必要拿来进行分享一下的就是懒加载了,还有相关的防抖和节流。因为在浏览器中这些都是属于很常见的性能优化,面试也是常考题。话不多说,速度发车。
什么是懒加载?懒加载实现了什么效果?
引言
像上图中的百度图片,有成千上万的图片,但是每个图片都是通过网络请求进行拿到。虽然是异步进行但是同时进行大量图片的请求,整个页面的渲染以及网络的请求资源的下载将会变得非常缓慢,影响用户观感体验。这对于前端网站来说是十分致命的缺陷。
在当今互联网时代,用户体验已成为衡量网站质量的重要指标之一。随着网页内容的日益丰富,特别是图片资源的大量使用,如何高效且快速地展示页面成为了前端开发中不可忽视的挑战。其中,“图片懒加载”技术便是解决这一问题的有效手段,它不仅能够提升页面加载速度,还能显著改善用户体验。
懒加载到底做了什么?
简单来说其实懒加载做的事情就是只加载用户屏幕目前所需要的图片,这里可能不是特别准确,但是大致意思就是加载目前用户屏幕所展示的图片,其他的图片不进行加载,只有当用户滑动页面的时候,其他图片进行判断加载(图片出现在用户屏幕中则进行加载)
这里提一嘴,只要浏览器已经加载过的图片就会加入到缓存中,浏览器可以直接从缓存中加载图片,而不是每次都重新发起网络请求。
懒加载原理是什么呢?为什么懒加载能控制图片的加载呢?
这里就不得不聊聊图片的特性了,其实只要图片具有src
属性,浏览器就会对该地址进行网络请求下载资源。懒加载就是通过判断加载(前面提过)然后给图片进行src
赋值,浏览器就会自动发送网络请求给资源地址进行下载。
懒加载实例和实现讲解
其实懒加载就是两点需要注意
- 如何控制img属性src赋值,并且图片地址存放在哪
- 什么时候进行加载什么时候不进行加载
关于第一点我的实现是使用自定义属性data-src
,data-
为前缀的属性是HTML5引入的一个特性,允许开发者在HTML元素上嵌入自定义的数据属性。这类属性为非标准的属性,提供了存储与元素相关的元数据的方式,而不会影响到HTML的语义结构。在JavaScript中,可以通过元素的dataset
属性轻松访问这些自定义数据属性。
这样我们就可以先使用data-src存储图片的资源地址,等到图片应当加载的时候,再进行src的赋值。
第二点我通过画图来解释
代码实现详解
实现步骤主要分为以下几点:
-
监听鼠标滚轮事件,因为只有鼠标进行滚动之后新的图片才有可能出现在屏幕中,所以这里我们进行鼠标滚轮监听,只要鼠标滚动进行了滚动我们就执行图片加载方法进行判断。
-
图片什么时候加载,主要需要做两件事情,第一件事情就是,判断图片是否进入到了屏幕中,这里我用的是
offsetTop
属性,offsetTop
是一个JavaScript DOM
属性,用于获取一个元素相对于其最近的具有定位(positioned)的父元素顶部的距离。如果元素的所有祖先元素都没有定位(默认的position: static
),那么offsetTop
会返回元素相对于整个文档顶部的距离。
这里只需要判断图片的offsetTop
属性(距离文档顶部的距离)是否 <= 滚轮已经滚动的距离scrollTop
+屏幕高度clientHeight
。让我画个图- ̗̀(๑ᵔ⌔ᵔ๑)
第二件事情就是通过dataset对象属性拿到自定义属性进行src的赋值,这一步知道dataset后就非常简单。
下面是我的实例代码,大家可以直接复制然后使用。
<!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">
</head>
<body>
<img data-price="20" data-src="https://www.toopic.cn/public/uploads/image/20200407/20200407210607_94155.jpg" />
<img data-src="https://www.toopic.cn/public/uploads/image/20200408/20200408214128_24416.jpg">
<img data-src="https://www.toopic.cn/public/uploads/small/1704296749480170429674998.jpg">
<img data-src="https://www.toopic.cn/public/uploads/small/1695608930939169560893045.jpg">
<img data-src="https://www.toopic.cn/public/uploads/small/1642755454773164275545428.jpg">
<img data-src="https://www.toopic.cn/public/uploads/image/20200411/20200411125828_78760.jpg">
<img data-src="https://www.toopic.cn/public/uploads/image/20200409/20200409221455_72056.jpg">
<img data-src="https://www.toopic.cn/public/uploads/image/20200407/20200407213848_17992.jpg">
<img data-src="https://www.toopic.cn/public/uploads/image/20200405/20200405223436_89821.jpg">
<img data-src="https://www.toopic.cn/public/uploads/image/20200411/20200411125228_17646.jpg">
<img data-src="https://www.toopic.cn/public/uploads/image/20200407/20200407205944_99274.jpg">
<img data-src="https://www.toopic.cn/public/uploads/image/20200411/20200411125355_54192.jpg">
<img data-src="https://www.toopic.cn/public/uploads/image/20200404/20200404183643_27556.jpg">
<img data-src="https://www.toopic.cn/public/uploads/image/20200407/20200407213757_91609.jpg">
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>
const imgs = document.querySelectorAll('img');
const num = imgs.length;
const screenHeight = document.documentElement.clientHeight;//一屏的高度
let n = 0;
document.addEventListener('DOMContentLoaded', () => {
loadImage();
})
function loadImage() {
console.log('1');
// 是否在可视区?
// 滚动条偏移量
// 不同浏览器兼容性问题
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
// console.log(screenHeight);
for (let i = n; i < num; i++) {
if (imgs[i].offsetTop < (scrollTop + screenHeight)) {
// console.log(imgs[i].dataset);
//数据属性
imgs[i].src = imgs[i].dataset.src;
// imgs[i].src = imgs[i].getAttribute('data-src');
n = i + 1;
if (n === num) {
window.removeEventListener('scroll', throttleLayLoad);
}
}
}
}
const throttleLayLoad = _.throttle(loadImage, 300);
window.addEventListener('scroll', throttleLayLoad);
loadImage();
</script>
</html>
防抖和节流
引言
其实防抖和节流非常相似,只是各自实现判断的条件不同。
首先我来介绍一下为什么需要防抖和节流,当你鼠标滚动的时候,触发监听事件的次数可能会有成百上千次,相同的图片加载方法也会执行上千次,其实并不是每次滚动都需要加载图片的,因为一个图片的高度需要你滚一会儿才能滚完。所以我们只需要在滚动的一段时间内触发一次图片加载方法就可以了。
相同的是,
两个方法都是通过定时器进行指定时间内的图片加载。不同的如下:
- 防抖:在一段时间内频繁触发的事件,只有在最后一次触发后的一段时间内没有再次触发,才会执行函数。
- 节流:确保一个函数在规定时间内只执行一次,即使在这段时间内多次触发,也保持固定的执行频率。
防抖方法详解
function debounce(func, delay) {
//定时器
let timer = null;
return function () {
// 当前时间段还有定时任务(图片加载函数)正在等待执行,取消timer(定时函数)
if (timer) clearTimeout(timer);
// 重新进入新的时间等待或者是时间段内第一次触发,给timer重新赋值
timer = setTimeout(function () {
//图片加载函数
imageLoad();
}, 500)
}
}
这样子,只要我在一段时间之内一直滚动的话,触发的也只有最后一次滚动执行的定时任务(图片加载)
节流方法详解
function throttle(func, delay) {
//定义一个定时器
let timer = null;
return function () {
// 当前时间段内已经执行过一次滚轮事件了,触发了一次定时任务(图片加载),不再执行图片加载函数了
if (timer) return;
//只有函数执行完或者第一次执行则再次执行
timer = setTimeout(function () {
func();
timer = null;
}, delay)
}
}
规定一段时间内,只能执行一次图片加载,也就是定时任务(图片加载)期间不允许再次执行
结语
图片懒加载作为前端性能优化的一项重要策略,其核心在于平衡资源加载与用户体验之间的关系。通过深入理解浏览器的工作机制,合理利用数据属性和JavaScript监听事件,我们可以有效提升网页的加载速度和响应性。此外,掌握防抖与节流等高级技巧,更是优化前端逻辑、提升代码效率的关键。
喜欢的话就点个关注和赞吧!谢谢- ̗̀(๑ᵔ⌔ᵔ๑)