前端优化 之 图片预加载和懒加载
Posted 永远没有404
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端优化 之 图片预加载和懒加载相关的知识,希望对你有一定的参考价值。
欢迎学习交流!!!
持续更新中…
预加载
什么是预加载
资源预加载是另一个性能优化技术,我们可以使用该技术来预先告知浏览器某些资源可能在将来会被使用到。预加载简单来说就是将所有所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。
为什么要用预加载
在网页全部加载之前,对一些主要内容进行加载,以提供给用户更好的体验,减少等待的时间。否则,如果一个页面的内容过于庞大,没有使用预加载技术的页面就会长时间的展现为一片空白,直到所有内容加载完毕。
场景举例:
当我们观看漫画时,如果看完一张,切换到下一张的漫画还未加载出来,需要空白时间进行等待,就会大大影响用户的体验感,浏览网页时也是如此。
预加载缺点:
- 预加载会占用较多的后台资源,因为可能一次性加载较多的图片
- 预加载需要比较长的时间 ,一般是利用用户进行其他操作时进行。(如漫画是在用户看上一个图片时进行预加载)。或者是在等待的这段时间显示其他。(如显示进度条)
预加载的实现
实现原理
让 img 标签先显示其他的图片,当其指向的真实图片缓存完成后,再显示为实际的图片。
CSS方法
- 创建用来预加载的标签
- 给标签使用背景图,背景图的路径是需要预加载的图片资源。并且将图片移到看不见的地方,或缩小到看不见。不能用
display=none
, 否则预加载会失效 - 当使用到已经预加载好的图片时,会直接使用缓存好的图片资源,而不需要向服务器发送请求。
<!--html文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSS 预加载</title>
<!-- 引入预加载样式文件 -->
<link rel="stylesheet" href="./preLoad.css">
</head>
<body>
<!-- 点击时显示图片 -->
<button onclick="show()">显示</button>
<ul>
<!-- 用来预加载的标签 -->
<li id="preImg1"/>
<li id="preImg2"/>
<li id="preImg3"/>
</ul>
</body>
<script>
var show = function ()
// 点击 ul 里的标签 ,显示图片
document.querySelector("ul").innerHTML =
`<li><img src="https://tse3-mm.cn.bing.net/th/id/OIP-C.gzfC-tfjMW3ckgMlTln9gQHaEV?pid=ImgDet&rs=1"></li>
<li><img src="https://tse1-mm.cn.bing.net/th/id/OIP-C.yrwsPVFmAUEPECn8DsgJfgHaEy?pid=ImgDet&rs=1"></li>
<li><img src="https://tse1-mm.cn.bing.net/th/id/OIP-C.hxoEaM5oD20OmIk7ilOHpQHaHa?pid=ImgDet&rs=1"></li>`
</script>
</html>
/* 预加载样式文件 */
img
width: 200px;
/* 预加载文件 */
#preImg1
background-image: url('https://tse3-mm.cn.bing.net/th/id/OIP-C.gzfC-tfjMW3ckgMlTln9gQHaEV?pid=ImgDet&rs=1');
width: 0;
height: 0; /* 隐藏用来预加载的标签 */
#preImg2
background-image: url('https://tse1-mm.cn.bing.net/th/id/OIP-C.yrwsPVFmAUEPECn8DsgJfgHaEy?pid=ImgDet&rs=1');
width: 0;
height: 0;
#preImg3
background-image: url('https://tse1-mm.cn.bing.net/th/id/OIP-C.hxoEaM5oD20OmIk7ilOHpQHaHa?pid=ImgDet&rs=1');
width: 0;
height: 0;
说明:
- 在浏览器打开第一次进行加载时,加载CSS时遇到需要加载背景图片资源,则会向服务器发送请求,服务器向浏览器返回图片资源放在浏览器的本地缓存中。
- 在开发者工具中可以查看到再未点击 显示 按钮时就有3个200的请求码。
- 而在点击了 显示 按钮后,浏览器不会向服务器发送任何请求。
JavaScript方法
- 将需要预加载的图片资源的 URL 保存在数组里
- 循环遍历 URL 数组执行以下步骤,直到结束
- 创建一个 image 对象
new Image()
- 将 image 对象的 src 属性的值指定为预加载图片的 URL
<!-- HTML 文件 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JS 实现图片预加载</title>
<!-- 简单的样式,不用关注 -->
<style>
ul
float: left;
margin: 0;
padding: 0;
li
list-style-type: none;
float: left;
img
width: 100px;
height: 100px;
#mask
position: absolute;
width: 300px;
height: 100px;
background-color: rgb(177, 177, 177);
line-height: 100px;
text-align: center;
color: rgb(255, 255, 255);
font-size: 32px;
font-weight: 600;
</style>
</head>
<body>
<!-- 设置遮罩层,显示加载进度 -->
<div id="mask">00%</div>
<ul>
<!-- 写好标签,会解析到此时会立马加载 -->
<!-- <li><img src="https://tse3-mm.cn.bing.net/th/id/OIP-C.gzfC-tfjMW3ckgMlTln9gQHaEV?pid=ImgDet&rs=1"></li>
<li><img src="https://tse1-mm.cn.bing.net/th/id/OIP-C.yrwsPVFmAUEPECn8DsgJfgHaEy?pid=ImgDet&rs=1"></li>
<li><img src="https://tse1-mm.cn.bing.net/th/id/OIP-C.hxoEaM5oD20OmIk7ilOHpQHaHa?pid=ImgDet&rs=1"></li> -->
</ul>
</body>
<!-- 引入预加载脚本文件 -->
<script src="./preLoad.js"></script>
</html>
// 预加载脚本文件
// 预加载的图片 URL
const urlList = [
'https://tse3-mm.cn.bing.net/th/id/OIP-C.gzfC-tfjMW3ckgMlTln9gQHaEV?pid=ImgDet&rs=1',
'https://tse1-mm.cn.bing.net/th/id/OIP-C.yrwsPVFmAUEPECn8DsgJfgHaEy?pid=ImgDet&rs=1',
'https://tse1-mm.cn.bing.net/th/id/OIP-C.hxoEaM5oD20OmIk7ilOHpQHaHa?pid=ImgDet&rs=1']
// 预加载函数 ,会在加载完毕后隐藏遮罩层
function preLoad()
let process = document.querySelector('#mask'), // 遮罩层 ,用于修改进度和隐藏
len = urlList.length,// 提出 URL 数组长度 ,提供性能
count = 0, // 计算已加载数量和修改进度
ul = document.querySelector("ul"), // 将图片放入此
imgList=""; // img 标签字符串临时存放点,避免刷新DOM的次数。
// 为了模拟多图片资源和将加载过程慢下来,这里使用了计时器 , 实际情况我们采用遍历 URL 数组。
let id = setInterval(() =>
let img = new Image()
img.src = urlList[count]
imgList += `<li><img src="$urlList[count]"></li>`
img.onload = img.onerror = function ()
count++;
process.innerText = (count / len * 100).toFixed(2) + '%'; // 设置进度百分比
if (count === len)
clearInterval(id)
ul.innerHTML += imgList;
process.style.display = 'none'
, 500)
// 调用预加载函数
preLoad()
说明:
- 当需要显示大量图片时,可以先显示其他或者有一些加载的提示。同时执行预加载函数。此处使用了遮罩层和进度显示。
- 预加载函数会加载图片资源并在本地缓存,但不会显示,有缓存。在加载的过程中,随着加载完成的数量增加,进度也会增加。
- 当全部加载完毕后,将图片动态添加到页面上,隐藏遮罩层。图片可被立即显示,无需再发送请求到服务器请求资源。
懒加载
什么是懒加载
懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式。用户滚动到它们之前,可视区域外的图像不会加载。这与图像预加载相反,在长网页上使用延迟加载将使网页加载更快。在某些情况下,它还可以帮助减少服务器负载。
当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,俗称占位图),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。
为什么要用懒加载
- 能提升用户的体验,在类电商类项目,往往存在大量的图片,如 banner 广告图,菜单导航图,美团等商家列表头图等。图片众多以及图片体积过大往往会影响页面加载速度,造成不良的用户体验。
- 减少无效资源的加载,这样能明显减少了服务器的压力和流量,也能够减小浏览器的负担。
- 防止并发加载的资源过多会阻塞js的加载,影响网站的正常使用。
懒加载的缺点:
- 需要监听图片是否显示,比较耗浏览器性能。
- 图片是显示时才去加载。如果网络不太好可能会有一段时间是空白
懒加载的实现
- 首先将页面上的图片的 src 属性设为空字符串,而图片的真实路径则设置在
data-original
属性中 - 当页面滚动的时候需要去监听scroll事件,在scroll事件的回调中,判懒加载的图片是否进入可视区域
- 如果图片在可视区内,将图片的 src 属性设置为
data-original
的值,即可实现延迟加载。 - 如果不在可视区内则不显示。
首先对于页面API的介绍:
描述 | API |
---|---|
页可见区域宽 | document.body.clientWidth; |
网页可见区域高 | document.body.clientHeight; |
网页可见区域宽 | document.body.offsetWidth (包括边线的宽); |
网页可见区域高 | document.body.offsetHeight (包括边线的宽); |
网页正文全文宽 | document.body.scrollWidth; |
网页正文全文高 | document.body.scrollHeight; |
网页被卷去的高 | document.body.scrollTop; |
网页被卷去的左 | document.body.scrollLeft; |
网页正文部分上 | window.screenTop; |
网页正文部分左 | window.screenLeft; |
屏幕分辨率的高 | window.screen.height; |
屏幕分辨率的宽 | window.screen.width; |
屏幕可用工作区高度 | window.screen.availHeight; |
HTMLElement.offsetTop
为只读属性,它返回当前元素相对于其 offsetParent
元素的顶部的距离。
window.innerHeight
:浏览器窗口的视口(viewport)高度(以像素为单位);如果有水平滚动条,也包括滚动条高度。
其中, 当 offsetTop <= scrollTop + clientHeight
时 , 图片便是显示出来或者在可视区之上了。
JavaScript方法
<script>
var num = document.getElementsByTagName('img').length;
var img = document.getElementsByTagName("img");
var n = 0; //存储图片加载到的位置,避免每次都从第一张图片开始遍历
lazyload(); //页面载入完毕加载可是区域内的图片
window.onscroll = lazyload;
function lazyload() //监听页面滚动事件
var seeHeight = document.documentElement.clientHeight; //可见区域高度
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滚动条距离顶部高度
for (var i = n; i < num; i++)
if (img[i].offsetTop < seeHeight + scrollTop)
if (img[i].getAttribute("src") == "default.jpg")
img[i].src = img[i].getAttribute("data-src");
n = i + 1;
</script>
jQuery方法
<script>
var n = 0,
imgNum = $("img").length,
img = $('img');
lazyload();
$(window).scroll(lazyload);
function lazyload(event)
for (var i = n; i < imgNum; i++)
if (img.eq(i).offset().top < parseInt($(window).height()) + parseInt($(window).scrollTop()))
if (img.eq(i).attr("src") == "default.jpg")
var src = img.eq(i).attr("data-src");
img.eq(i).attr("src", src);
n = i + 1;
</script>
懒加载优化
前面有提到懒加载的缺点,它对服务器友好,对浏览器却不友好。因为一直监听滚动事件,一直触发是非常消耗性能的 。
对此我们可以进行防抖和节流来减少性能的消耗 、提高流畅度。
详解请看:JS的防抖和节流
预加载和懒加载的比较
概念:
- 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。
- 懒加载也叫延迟加载:JS图片延迟加载,延迟加载图片或符合某些条件时才加载某些图片。
区别:
- 两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。
优秀文章:
超详细的图片预加载和懒加载教程
懒加载和预加载
以上是关于前端优化 之 图片预加载和懒加载的主要内容,如果未能解决你的问题,请参考以下文章