1. 懒加载
懒加载也叫做延迟加载、按需加载,指的是在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。
在比较长的网页或应用中,如果图片很多,所有的图片都被加载出来,而用户只能看到可视窗口
的那一部分图片数据,这样就浪费了性能。
如果使用图片的懒加载就可以解决以上问题。在滚动屏幕之前,可视化区域之外的图片不会进行加载,在滚动屏幕时才加载。这样使得网页的加载速度更快,减少了服务器的负载。
懒加载适用于图片较多,页面列表较长(长列表)的场景中。
特点
- 减少无用资源的加载:使用懒加载明显减少了服务器的压力和流量,同时也减小了浏览器的负担。
- 提升用户体验: 如果同时加载较多图片,可能需要等待的时间较长,这样影响了用户体验,而使用懒加载就能大大的提高用户体验。
- 防止加载过多图片而影响其他资源文件的加载 :会影响网站应用的正常使用。
实现原理
图片的加载是由 src 引起的,当对 src 赋值时,浏览器就会请求图片资源。
根据这个原理,我们使用 HTML5 的 data-xxx 属性来储存图片的路径,在需要加载图片的时候,将 data-xxx 中图片的路径赋值给src,这样就实现了图片的按需加载,即懒加载。
注意:data-xxx 中的 xxx 可以自定义,这里我们使用 data-src 来定义。
懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。
使用简单js书写懒加载的实现
- 浏览器可视区高度
window.innerHeight
- 浏览器滚动的过的距离
document.body.scrollTop
或者
document.documentElement.scrollTop
- 元素顶部距离文档顶部的高度
imgs.offsetTop
imgs是将要显示的元素
实现条件:img.offsetTop < window.innerHeight + document.body.scrollTop
代码
<style>
.imgs {
width: 500px;
background-color: #aaa;
border: 1px solid #ddd;
margin: 0 auto;
padding: 10px;
}
img {
width: 100%;
height: 300px;
margin: 5px 0;
}
</style>
<div class="imgs">
<img src="../CSS/资源包/img/loading.jpg" alt="" data-src="../CSS/资源包/img/1.webp">
<img src="../CSS/资源包/img/loading.jpg" alt="" data-src="../CSS/资源包/img/2.webp">
<img src="../CSS/资源包/img/loading.jpg" alt="" data-src="../CSS/资源包/img/3.webp">
<img src="../CSS/资源包/img/loading.jpg" alt="" data-src="../CSS/资源包/img/4.webp">
<img src="../CSS/资源包/img/loading.jpg" alt="" data-src="../CSS/资源包/img/5.webp">
<img src="../CSS/资源包/img/loading.jpg" alt="" data-src="../CSS/资源包/img/6.webp">
<img src="../CSS/资源包/img/loading.jpg" alt="" data-src="../CSS/资源包/img/7.webp">
<img src="../CSS/资源包/img/loading.jpg" alt="" data-src="../CSS/资源包/img/8.webp">
</div>
<script type="text/javascript">
function lozyLoad() {
const imgs = document.querySelectorAll('img')
console.log(imgs);
let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
let winHeight = window.innerHeight;
console.log('--------', scrollTop, winHeight);
for (var i = 0; i < imgs.length; i++) {
console.log(i, imgs[i].offsetTop);
if (imgs[i].offsetTop < scrollTop + winHeight) {
imgs[i].src = imgs[i].getAttribute('data-src')
}
}
}
lozyLoad()
window.addEventListener('scroll', function() {
lozyLoad()
});
</script>
方法有很多哦~ 此例举出最易明白的
2.回流与重绘
概念
回流
当渲染树中部分或者全部元素的尺寸、结构或者属性发生变化时,浏览器会重新渲染部分或者全部文档的过程就称为回流。
重绘
当页面中某些元素的样式发生变化,但是不会影响其在文档流中的位置时,浏览器就会对元素进行重新绘制,这个过程就是重绘。
触发条件
回流
- 页面的首次渲染
- 浏览器的窗口大小发生变化
- 元素的内容发生变化
- 元素的尺寸或者位置发生变化
- 元素的字体大小发生变化
- 激活 CSS 伪类
- 查询某些属性或者调用某些方法
- 添加或者删除可见的 DOM 元素
在触发回流(重排)的时候,由于浏览器渲染页面是基于流式布局的,所以当触发回流时,会导致周围的 DOM 元素重新排列,它的影响范围有两种:
全局范围:从根节点开始,对整个渲染树进行重新布局
局部范围:对渲染树的某部分或者一个渲染对象进行重新布局
重绘
下面这些操作会导致重绘:
color、background 相关属性:background-color、background-image等
outline 相 关 属 性 : outline-color 、 outline-width 、text-decoration、border-radius、visibility、box-shadow
注意: 当触发回流时,一定会触发重绘,但是重绘不一定会引发回流。
避免方法
减少回流与重绘的措施:
- 操作 DOM 时,尽量在低层级的 DOM 节点进行操作
- 不要使用 table 布局, 一个小的改动可能会使整个 table 进行重新布局
- 使用 CSS 的表达式
- 不要频繁操作元素的样式,对于静态页面,可以修改类名,而不是样式。
- 使用 absolute 或者 fixed,使元素脱离文档流,这样他们发生变化就不会影响其他元素
- 避免频繁操作 DOM,可以创建一个文档片段 documentFragment,在它上面应用所有 DOM 操作,最后再把它添加到文档中
- 将元素先设置 display: none,操作结束后再把它显示出来。因为在display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘。
- 将 DOM 的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写。这得益于浏览器的渲染队列机制。
- 浏览器针对页面的回流与重绘,进行了自身的优化——渲染队列浏览器会将所有的回流、重绘的操作放在一个队列中,当队列中的作到了一定的数量或者到了一定的时间间隔,浏览器就会对队列进行批处理。这样就会让多次的回流、重绘变成一次回流重绘。
上面,将多个读操作(或者写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,原本应该是触发多次回流,变成了只触发一次回流。
优化动画
对于如何优化动画,我们知道,一般情况下,动画需要频繁的操作DOM,就就会导致页面的性能问题,我们可以将动画的 position 属性设置为 absolute 或者 fixed,将动画脱离文档流,这样他的回流就不会影响到页面了。
防抖和节流
概念
函数防抖 是指在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。这可以使用在一些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。
函数节流 是指规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。节流可以使用在 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率。
应用场景
防抖
按钮提交场景:防⽌多次提交按钮,只执⾏最后提交的⼀次
服务端验证场景:表单验证需要服务端配合,只执⾏⼀段连续的输⼊事 件 的 最 后 ⼀ 次 ,还 有 搜 索 联 想 词 功 能 类 似 ⽣ 存 环 境 请 ⽤lodash.debounce
…
节流
拖拽场景:固定时间内只执⾏⼀次,防⽌超⾼频次触发位置变动
缩放场景:监控浏览器 resize
动画场景:避免短时间内多次触发动画引起性能问题
函数
防抖函数
<button class="btn">按钮</button>
function debounce(fn, wait) {
let timer = null;
return function() {
let context = this;
args = [...arguments];
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(context, args)
}, wait);
}
}
function consoleFun() {
console.log(123456);
}
const btn = document.querySelector('.btn')
//当点击按钮后 1秒 后输出 123456 ,持续点出,也只会在最后一次开始计时1s后输出
btn.addEventListener('click', debounce(consoleFun, 1000))
节流函数
- 时间戳
<button class="btn">按钮</button>
function throttle(fn, delay) {
let preTime = Date.now();
return function() {
let context = this;
let nowTime = Date.now();
let args = [...arguments];
console.log(nowTime, preTime, nowTime - preTime);
if (nowTime - preTime >= delay) {
preTime = Date.now();
return fn.apply(context, args)
}
}
}
function consoleFun() {
console.log('输出', 123456);
}
const btn = document.querySelector('.btn')
btn.addEventListener('click', throttle(consoleFun, 1000));//时间超过设定值就能触发,毫秒
- 定时器
function throttle(fn, wait) {
let timeout = null;
return function() {
let context = this;
let args = [...arguments];
if (!timeout) {
timeout = setTimeout(() => {
fn.apply(context, args)
timeout = null
}, wait);
}
}
}
function consoleFun() {
console.log('输出', 123456);
}
const btn = document.querySelector('.btn')
btn.addEventListener('click', throttle(consoleFun, 500))
对图片进行优化
- 不用图片。很多时候会使用到很多修饰类图片,其实这类修饰图片完全可以用 CSS 去代替。
- 对于移动端来说,屏幕宽度就那么点,完全没有必要去加载原图浪费带宽。一般图片都用 CDN 加载,可以计算出适配屏幕的宽度,然后去请求相应裁剪好的图片。
- 小图使用 base64 格式
- 将多个图标文件整合到一张图片中(雪碧图:加载出一个图片之后,使用哪个图标就直接定位位置)
- 选择正确的图片格式:对于能够显示 WebP 格式的浏览器尽量使用 WebP 格式。因为 WebP格式具有更好的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量,缺点就是兼容性并不好小图使用 PNG,其实对于大部分图标这类图片,完全可以使用 SVG 代替照片使用 JPEG。
扩展
图片格式及使用场景:
(1)BMP,是无损的、既支持索引色也支持直接色的点阵图。这种图片格式几乎没有对数据进行压缩,所以 BMP 格式的图片通常是较大的文件。
(2)GIF 是无损的、采用索引色的点阵图。采用 LZW 压缩算法进行编码。文件小,是 GIF 格式的优点,同时,GIF 格式还具有支持动画以及透明的优点。但是 GIF 格式仅支持 8bit 的索引色,所以 GIF 格式适用于对色彩要求不高同时需要文件体积较小的场景。
(3)JPEG 是有损的、采用直接色的点阵图。JPEG 的图片的优点是采用了直接色,得益于更丰富的色彩,JPEG 非常适合用来存储照片,与 GIF 相比,JPEG 不适合用来存储企业 Logo、线框类的图。因为有损压缩会导致图片模糊,而直接色的选用,又会导致图片文件较 GIF更大。
(4)PNG-8 是无损的、使用索引色的点阵图。PNG 是一种比较新的图片格式,PNG-8 是非常好的 GIF 格式替代者,在可能的情况下,应该尽可能的使用 PNG-8 而不是 GIF,因为在相同的图片效果下,PNG-8具有更小的文件体积。除此之外,PNG-8 还支持透明度的调节,而 GIF并不支持。除非需要动画的支持,否则没有理由使用 GIF 而不是 PNG-8。
(5)PNG-24 是无损的、使用直接色的点阵图。PNG-24 的优点在于它压缩了图片的数据,使得同样效果的图片,PNG-24 格式的文件大小要比 BMP 小得多。当然,PNG24 的图片还是要比 JPEG、GIF、PNG-8大得多。
(6)SVG 是无损的矢量图。SVG 是矢量图意味着 SVG 图片由直线和曲线以及绘制它们的方法组成。当放大 SVG 图片时,看到的还是线和曲线,而不会出现像素点。这意味着 SVG 图片在放大时,不会失真,所以它非常适合用来绘制 Logo、Icon 等。
(7)WebP 是谷歌开发的一种新图片格式,WebP 是同时支持有损和无损压缩的、使用直接色的点阵图。从名字就可以看出来它是为 Web 而生的,什么叫为 Web 而生呢?就是说相同质量的图片,WebP 具有更小的文件体积。现在网站上充满了大量的图片,如果能够降低每一个图片的文件大小,那么将大大减少浏览器和服务器之间的数据传输量,进而降低访问延迟,提升访问体验。目前只有 Chrome 浏览器和 Opera浏览器支持 WebP 格式,兼容性不太好。
注:
在无损压缩的情况下,相同质量的 WebP 图片,文件大小要比 PNG 小26%;
在有损压缩的情况下,具有相同图片精度的 WebP 图片,文件大小要比 JPEG 小 25%~34%;
WebP 图片格式支持图片透明度,一个无损压缩的 WebP 图片,如果要支持透明度只需要 22%的格外文件大小。
⽤webpack 来优化前端性能
⽤webpack 优化前端性能是指:优化 webpack 的输出结果,让打包的最终结果在浏览器运⾏快速⾼效。
- 压缩代码:删除多余的代码、注释、简化代码的写法等等⽅式。可以利⽤webpack的 UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩JS⽂件, 利⽤ cssnano (css-loader?minimize)来压缩 css
- 利⽤CDN 加速: 在构建过程中,将引⽤的静态资源路径修改为 CDN 上对应的路径。可以利⽤webpack 对于 output 参数和各 loader 的publicPath 参数来修改资源路径
- Tree Shaking: 将代码中永远不会⾛到的⽚段删除掉。可以通过在启动 webpack 时追加参数 --optimize-minimize 来实现
- Code Splitting: 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存
- 提取公共第三⽅库: SplitChunksPlugin 插件来进⾏公共模块抽取, 利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码
提⾼webpack 的构建速度
- 多⼊⼝情况下,使⽤ CommonsChunkPlugin 来提取公共代码
- 通过 externals 配置来提取常⽤库
- 利⽤ DllPlugin 和 DllReferencePlugin 预编译资源模块 通过DllPlugin 来对那些我们引⽤但是绝对不会修改的 npm 包来进⾏预编译,再通过 DllReferencePlugin 将预编译的模块加载进来。
- 使⽤ Happypack 实现多线程加速编译
- 使⽤ webpack-uglify-parallel 来提升 uglifyPlugin 的压缩速度。原理上 webpack-uglify-parallel 采⽤了多核并⾏压缩来提升压缩速度
- 使⽤ Tree-shaking 和 Scope Hoisting 来剔除多余代码
内存泄漏
以下四种情况会造成内存的泄漏:
意外的全局变量:由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。
被遗忘的计时器或回调函数:设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留在内存中,而无法被回收。
脱离 DOM 的引用:获取一个 DOM 元素的引用,而后面这个元素被删除,由于一直保留了对这个元素的引用,所以它也无法被回收。
闭包:不合理的使用闭包,从而导致某些变量一直被留在内存当中。
文章字多数手打,如有细节错误,请指出,谢谢!!!