惰性加载:优化资源管理与提升用户体验的现代策略
前言
什么是懒加载?
懒加载(Lazy Loading),又称为延迟加载或按需加载,是一种编程模式和优化策略,用于推迟对象的初始化、数据的加载或资源的获取,直到它们真正被需要时才进行。
懒加载的意义:
- 提升页面加载速度:通过只加载可视区域的内容或用户即将查看的内容,懒加载显著减少了首次页面加载所需的时间,使页面能够更快地呈现给用户,提高了用户体验。
- 降低服务器负担:由于不是一次性加载所有资源,而是分批按需加载,这减少了服务器同时处理的请求数量和数据传输量,有助于降低服务器压力和带宽消耗。
- 提升系统性能:特别是在数据量庞大的应用中,如长列表、大型图像库等,懒加载可以有效减少内存占用,防止因一次性加载过多数据导致的系统响应缓慢或崩溃。
- 适应性更强:懒加载机制可以根据设备性能、网络状况动态调整加载策略,为不同条件下的用户提供最适合的加载体验。
正文
思考一下
如果有很多图片时,图片全部用src来存取图片路径,这个时候可能页面的加载就会比较慢,这个时候我们可以采用懒加载的思想,即先加载一个屏幕内的图片,当滑动滚动条的时候,再加载该屏幕内的图片,所以
我们把图片的地址放在data-src
中,src
中放一个空白的照片的地址,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>懒加载</title>
<style>
body{
background-color: #96e173;
}
img {
display: block;
margin-bottom: 50px;
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<!-- data-src为数据属性 -->
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567641974410_img_000" />
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567641293753_img_png">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567642423719_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190808/v2_1565254363234_img_jpg">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567642425030_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567642425101_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567642425061_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190904/v2_1567591358070_img_jpg">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567640518658_img_png">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567641974410_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567641974454_img_000">
</body>
</html>
js部分
大概的思路:
- 给
window
绑定一个滚动事件,当滚动时触发回调函数lazyload
回调函数lazyload:
- 通过
document.documentElement.clientHeight
获取可视区域的一屏的高度screenHeight
; - 通过
document.documentElement.scrollTop
获取滚动条距离顶部的距离scrollTop
,也就是滚动条滚动的距离,但是这里鉴于浏览器的兼容性应该写成document.documentElement.scrollTop || document.body.scrollTop
; - 通过for循环遍历图片,通过
imgList[i].offsetTop < screenHeight + scrollTop
(图片距离顶部的距离<一屏的高度+滚动的高度)判断该图片否在可视区域内,如果在就将data-src
赋值给src
; - 用一个变量
n
来记录已经渲染的图片的数量,用来判断图片是否已经全部渲染完,全部渲染完就移除window
的滚动事件监听。
<script>
const imgList = document.getElementsByTagName('img');
const num = imgList.length;
let n = 0;
window.addEventListener('scroll', throttleLazyload);
function lazyload() {
// 获取可视区域一屏的高度
let screenHeight = document.documentElement.clientHeight;
// console.log(screenHeight);
// 获取滚动条滚动的距离 多浏览器适配
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
console.log(scrollTop);
for (let i = n; i < num; i++) {
if(imgList[i].offsetTop < screenHeight + scrollTop) {
imgList[i].src = imgList[i].getAttribute('data-src');
// 记录已经加载过的图片的下标
n = i + 1;
if(n === num) {
console.log('所有图片加载完成');
window.removeEventListener('scroll', throttleLazyload)
}
}
}
}
</script>
优化
- 上面的代码已经基本可以实现效果了,但是要注意,前端一定要注意性能的优化,性能优化有防抖和节流等方法,这里要用到的方法是节流,因为当滚动条上下来回滚动时,会一直渲染已经渲染过的图片,所有我们要通过节流来处理这个问题。
节流函数:
// 节流函数
function throttle(func, limit) {
//记录当前是否在节流状态
let inThrottle;
//返回一个函数用于作为节流包装后的函数
return function() {
// 保存当前调用的上下文和参数
const context = this;
const args = arguments;
// 如果不在节流状态
if (!inThrottle) {
//调用原函数,并传递当前的上下文和参数
func.apply(context, args);
//将状态设置为节流状态中,阻止下一次的立即执行
inThrottle = true;
//使用定时器在limit时间后重置节流状态,允许下一次执行
setTimeout(() => inThrottle = false, limit);
}
}
}
- 第一次页面的图片应该在未滚动之前就调用一次回调函数,使用一个事件
DOMCententLoaded
DOMContentLoaded事件:
当浏览器完成页面的初始HTML文档的加载和解析时触发,此时DOM树构建完成,而无需等待样式表、图片和子框架等异步资源完成加载。
// DOMContentLoaded html和css页面加载完成时触发,保证第一次页面的图片不用滚轮加载图片
document.addEventListener('DOMContentLoaded', () => {
console.log('DOMContentLoaded');
lazyload();
})
代码简化
可以不用写节流函数,而是通过引入lodash
库,调用里面的_.throttle
方法。
总代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>懒加载</title>
<style>
body{
background-color: pink;
}
img {
display: block;
margin-bottom: 50px;
width: 400px;
height: 400px;
}
</style>
</head>
<body>
<!-- data-src为数据属性 -->
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567641974410_img_000" />
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567641293753_img_png">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567642423719_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190808/v2_1565254363234_img_jpg">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567642425030_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567642425101_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567642425061_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190904/v2_1567591358070_img_jpg">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567640518658_img_png">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567641974410_img_000">
<img src = 'https://misc.360buyimg.com/mtd/pc/common/img/blank.png' data-src="https://img.36krcdn.com/20190905/v2_1567641974454_img_000">
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script>
const imgList = document.getElementsByTagName('img');
const num = imgList.length;
let n = 0;
// 注册在scroll事件中的触发函数
const throttleLazyload = _.throttle(lazyload, 200);
window.addEventListener('scroll', throttleLazyload);
// DOMContentLoaded html和css页面加载完成时触发,保证第一次页面的图片不用滚轮加载图片
document.addEventListener('DOMContentLoaded', () => {
console.log('DOMContentLoaded');
lazyload();
})
function lazyload() {
// 获取可视区域一屏的高度
let screenHeight = document.documentElement.clientHeight;
// console.log(screenHeight);
// 获取滚动条滚动的距离 多浏览器适配
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
console.log(scrollTop);
for (let i = n; i < num; i++) {
if(imgList[i].offsetTop < screenHeight + scrollTop) {
imgList[i].src = imgList[i].getAttribute('data-src');
// 记录已经加载过的图片的下标
n = i + 1;
if(n === num) {
console.log('所有图片加载完成');
window.removeEventListener('scroll', throttleLazyload)
}
}
}
}
// // 节流函数
// function throttle(func, limit) {
// //记录当前是否在节流状态
// let inThrottle;
// //返回一个函数用于作为节流包装后的函数
// return function() {
// // 保存当前调用的上下文和参数
// const context = this;
// const args = arguments;
// // 如果不在节流状态
// if (!inThrottle) {
// //调用原函数,并传递当前的上下文和参数
// func.apply(context, args);
// //将状态设置为节流状态中,阻止下一次的立即执行
// inThrottle = true;
// //使用定时器在limit时间后重置节流状态,允许下一次执行
// setTimeout(() => inThrottle = false, limit);
// }
// }
// }
</script>
</body>
</html>
效果:
当滚动条滑动到底部时,表示所有的图片已经加载完成,此时控制台也不会输出了。
结语
转载自:https://juejin.cn/post/7379873506543255562