优化系列之懒加载与预加载 - junruchen/junruchen.github.io GitHub Wiki
性能优化中的图片优化。
目录
- 懒加载
- 缓预加载
- webP
- 关于图片优化的其他方案
- svg与雪碧图
- 图片压缩与域名处理
- 关于图片的扩展知识
- 图片是否需要Gzip压缩
- 图片在日志上报中的使用
即只有当图片出现在浏览器的可视区域时,才去加载图片,在加载之前使用一张默认图片或者背景色代替。
优点是:减少页面加载时的图片请求,减轻服务器压力,减少页面的加载时间。
主要是依据:页面中的img
元素只有存在src
属性时,浏览器才会发送网络请求 这一特性来实现。
步骤:
- 为图片设置一个可以记录图片路径的属性,如
data-src
- 监听页面滚动,当图片出现在可视区域时,设置图片的
src
为data-src
下面是一个简单的例子:
/* -设置加载时、加载完成的样式- */
.lazy {
opacity: 0;
min-height: 200px;
transition: opacity .5s linear;
}
.lazy.loaded {
opacity: 1;
}
react中使用的简单写法
import React, { useEffect } from 'react';
// 配置项
const placeHolder = 'placeholder.png' // 默认图片地址,也可直接设置图片背景色
const threshold = 200 // 距离视窗底部多少像素开始加载
const lazyClss = 'loaded' // 加载成功后样式,用来增加过滤动画等效果
function LazyloadImg() {
// 需要展示的大量图片
const imgUrl = [
'https://cdn.dribbble.com/users/772985/screenshots/7043973/pika_1_1x.jpg',
...
]
useEffect(() => {
const domScroll = () => {
const clientHeight = document.documentElement.clientHeight || window.innerHeight
document.querySelectorAll('.lazy').forEach(el => {
// 设置默认图
if (placeHolder && !el.src) {
el.src = placeHolder
}
// 判断当图片在可视区内时,加载图片,并设置样式
const imageTop = el.getBoundingClientRect().top
const dataSrc = el.getAttribute('data-src')
if (imageTop <= clientHeight + threshold && el.src !== dataSrc) {
el.src = dataSrc
if (lazyClss) {
el.classList.add(lazyClss)
}
}
});
}
domScroll()
window.addEventListener('scroll', domScroll)
return () => {
window.removeEventListener('resize', domScroll)
}
}, [])
return (
<div>
{imgUrl.map((item, idx) =>
<img className="lazy" data-src={item} key={idx} alt={'图片' + idx} width="100%" />)
}
</div>
);
}
export default LazyloadImg;
即将所需资源提前加载到本地,等需要时直接从缓存中获取资源。
优点是:在页面记载之前对主要资源进行预加载,减少用户等待时间。
1、借助img标签
<img src="xxx" style="display:none"/>
2、使用XMLHttpRequest,会存在跨域问题
const xmlhttprequest = new XMLHttpRequest();
xmlhttprequest.onreadystatechange = callback;
xmlhttprequest.open('GET', urls[0], true);
xmlhttprequest.send();
function callback() {
if (xmlhttprequest.readyState === 4 && xmlhttprequest.status === 200) {
console.log('success', xmlhttprequest.responseText)
} else {
console.log('error');
}
}
3、使用 Image()
对象,较常用的方式
//预加载
function preloadImg (urls, callback) {
const images = [];
const successImgs = [];
const errorImgs = [];
const done = () => {
if (successImgs.length + errorImgs.length === images.length) {
callback({
success: successImgs.length,
error: errorImgs.length,
successImgs,
errorImgs
});
}
}
if (typeof urls === 'string') {
urls = [urls];
}
urls.forEach((url) => {
const idx = images.length
images[idx] = new Image();
images[idx].src = url;
images[idx].onload = function () {
successImgs.push(this);
done();
};
images[idx].onerror = function () {
errorImgs.push(this);
done();
}
})
}
// 使用
preloadImg(images, (res)=> {
// 其他处理
});
两者均可达到页面性能优化的效果,区别是,懒加载可降低服务器压力,而预加载会增加服务器压力。
svg图片的特性:
- 矢量图形,不论是放大还是缩小,展示效果都是一样的
- 矢量图是使用相对点保存数据的,与位图的像素点相比,svg格式的图片大小更小,因此响应也更快一些
- svg图形具有可控性,可自由的更改颜色、增加动画等。
雪碧图的优点:
- 将多个图片合并为一张图片,减少网络请求,减小图片的总大小
- 维护更方便,多应用于网页图标等
在传统的项目中,大多是直接将多个小图组合为一张大的图片,然后借助background中的background-position
属性进行图标定位。
而随着Iconfont等各类图标库的兴起,svg中的symbol
元素可以说是雪碧图的最佳实践了。
下面是一个symbol引用的例子
<!--Icon-->
<svg>
<symbol id="icon-windows" viewBox="0 0 1024 1024">
<path d="M491.18331146 178.94070816L907.5078125 116.4921875v370.52902222H491.18331146z" ></path>
<path d="M116.4921875 233.06348037l319.1809845-47.18439102v305.30422212H116.4921875z" ></path>
<path d="M491.18331146 845.05929184L907.5078125 907.5078125V546.69345093H491.18331146z" ></path>
<path d="M116.4921875 790.93651963l319.1809845 47.18439102V546.69345093H116.4921875z" ></path>
</symbol>
</svg>
<!--使用-->
<svg class="icon" aria-hidden="true">
<use :xlink:href="#icon-windows"></use>
</svg>
如果项目中存在大量图标,建议使用iconfont引入的形式。
对于静态图片,在使用之前可使用类似 TingPNG 的工具进行无损压缩,并引入cdn缓存。
对于用户上传的图片,如果只是上传到个人服务器,可压缩后上传。如上传到图片云存储平台,则可使用平台支持的对象处理策略,对图片进行压缩、裁剪等处理。
如果条件允许,可为图片配置单独的域名,或使用http2.0来避开网络请求的数量限制。
不需要!
网站开启gzip压缩,是比较常见的优化方案。浏览器默认只会启动html文件的压缩,css、js文件等需要额外配置,点击查看启动gzip的详细配置。
对于图片、flash的swf文件等是不需要做gzip压缩的,主要原因是这类资源本身就压缩,开启Gzip压缩后体积也不会有太大的变化,反而浪费资源