常见的前端性能优化手段总结

5,034 阅读6分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。

加载时

1.减少HTTP请求。

Web 前端 80% 的响应时间花在图片、样式、脚本等资源下载上。

一个 HTTP 请求要经历一个复杂的流程: DNS查找 – TCP握手(三次握手)  – 浏览器发出HTTP请求 – 服务器接收请求 – 服务器处理请求和响应结果 – 浏览器接收请求 – TCP断开连接(四次挥手)。

因为一个HTTP请求就要经历这上述等一系列复杂的过程,这还是在不考虑网络环境因素的情况下的,所以当请求比较多时,这就直接体现在性能的消耗上了,这也就是为什么要将多个小文件合并成一个大文件,减少HTTP请求次数的重要原因了。

如果服务器支持HTTP2,那么HTTP2的新特性多路复用(MultiPlexing)能够有效的解决这个问题。

2.使用服务端渲染。

客户端渲染经历流程:获取HTML文件 – 按需要再获取JS文件 – 运行文件 – 生成DOM – 将DOM插入HTML中 – 最后再渲染页面。

服务端渲染流程:只要获取识别解析HTML文件即可。而且服务端渲染还能有效增强站点的SEO。

3.静态资源使用CDN。

什么是CDN:内容分发网络。它是一组分布在多个不同地理位置的Web服务器。我们都知道,当服务器离用户越远,延迟就越高,CDN就是为了解决这一问题,在多个位置布置服务器,让用户离服务器更近,缩短请求时间。

4.CSS写头部,JS写底部。

我们知道CSS和JS都会阻塞页面的渲染,如果这些文件要加载和解析很久的话,页面就会呈现空白,也就是我们常说的白屏问题。

那么CSS为什么可以放头部:因为如果先加载HTML再去加载CSS,会让用户第一时间看到页面是没有样式的,网站会很丑陋,用户体验会很不友好。

当然其实JS也可以放头部:只要给它加上defer或者async属性就可以了,异步下载,延迟执行。

关于 defer 与 async 区别:

  • script :加载和执行是同步、顺序的,没有兼容性问题,但会阻塞DOM的渲染,可能会导致长时间的白屏。
  • script defer:异步下载,延迟执行,会等整个页面都解析完毕后执行,延迟的脚本是有顺序的,但有兼容性问题。
  • script async:异步下载,延迟执行,但不保证等整个页面解析完毕后再执行,它是乱序的,这也比较适用百度或者谷歌分析这类不依赖其他脚本的库,有兼容性问题。

image.png

5.字体图标代替图片。

字体图标是矢量图,不会失真、字体图标文件也小、还能能设置font-size/color等属性,使用更加方便灵活。

6.使用HTTP缓存。

缓存针对的是第二次请求,缓存主要是在内存和硬盘。

HTTP缓存主要分为强缓存和协商缓存。

  • 强缓存:在过期日期未到时,不需要请求服务器,像饮料的过期日期一样,状态码是灰色的200。
  • 协商缓存:浏览器和服务器通过标识进行协商,标识匹配上,就让浏览器直接读缓存,标识匹配不上就返回新资源,状态码为304。

更多具体细节可以查看小编的另一篇文章 前端需要了解的浏览器缓存(即HTTP缓存)

7.图片优化。

(1)图片懒加载。原理是先不给图片设置路径,只有当图片进入可视区域内才去设置。

图片懒加载关键点是如何判断图片进入可视区域内:
方法一:IntersectionObserver
方法二:el.getBoundingClientRect()
方法三:原生 JS 判断
具体细节可以参考该文的懒加载指令 Vue3自定义指令-10个常见的实用指令,带详细讲解,快拿去收藏!!!

(2)图片压缩质量。其实60%~100%质量的图片通常是看不出来区别的。
(3)用CSS3里样式、动画替换一些图片效果。如小三角形、小箭头、一些简单的gif动画,因为通常代码的质量是图片质量的几分之一或者几十分之一。
(4)一些图标可以使用雪碧图。

8.其他小手段

(1)利用webpack分割代码,提取公共文件,防止主文件过于庞大,导致首屏加载过慢。
(2)第三方库可以单独提取独立文件,UI框架组件按需加载。
(3)减少ES6转换成ES5的冗余代码。
(4)压缩JS与CSS代码。
(5)删除无用代码console/alert/注解等。
(6)启用GZIP。

运行时

1.避免大量DOM元素与深层镶嵌

大量的DOM元素与深层镶嵌的DOM层级都会造成HTML解析过慢,我们要尽量避免不必要的DOM元素与深层镶嵌的出现。

可以通过如下API获取页面存在的DOM数量:

document.getElementsByTagName('*').length

2.减少回流和重绘。

回流必将引起重绘,重绘不一定引起回流。

(1)JS修改样式时,最好不要直接写样式,而是替换class来改变样式。
(2)JS操作DOM时,可以把DOM元素脱离文档流,可以借助隐藏元素(display:none)或者文档碎片。

3.降低CSS选择器的复杂性。

!important > 行内样式 > id > class > 标签名和伪类 > * > 继承 > 默认

CSS选择器优先级算法:
1.如果存在内联样式,那么A = 1,否则 A = 0;
2.B 的值等于ID选择器出现的次数;
3.C的值等于类选择器和属性选择器和伪类出现的总次数;
4.D的值等于标签选择器和伪元素出现的总次数。

通用选择器(*)没有优先级值(0,0,0,0)。

4.使用弹性布局(flexbox)

使用flex布局,性能更好,虽然兼容性有点差,不过是未来布局的发展方向,现代浏览器也都支持了。

5.用transform等新属性来实现动画。

使用transform、opacity、filter、will-change等属性来实现动画效果,它们不会触发回流和重绘,它们由单独的合成器单独处理,会启动硬件加速,也就是GPU加速。

6.使用事件委托。

事件委托利用冒泡的原理,能统一处理一类事件程序。

7.防抖和节流。

防抖:输入框的实时搜索、页面触发resize事件。
节流:滚动事件。

8.不要覆盖原始方法。

JS的代码无论如何优化,也比不上原生方法,原生方法是用底层语言写的,更具有性能优势。






至此,本篇文章就写完啦,撒花撒花。

image.png

希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。