前端性能优化
Posted wangziqiang123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端性能优化相关的知识,希望对你有一定的参考价值。
客户端优化
静态资源优化
-
使用构建工具对html,CSS,JS压缩,删除生产环境下的无用代码(比如注释,打印信息等)。
-
提取公共资源,减少代码体积。
-
外链CSS和JS文件,外链的文件可以放到CDN,服务器和浏览器会进行缓存。
-
使用雪碧图,减少http请求数。
自动生成雪碧图:https://www.toptal.com/developers/css/sprite-generator
-
使用字体图标iconfont:
-
图片使用webp格式
-
缓存(Service Worker)
[https://github.com/youngwind/blog/issues/113](https://github.com/youngwind/blog/issues/113) [https://fed.renren.com/2017/10/04/service-worker/](https://fed.renren.com/2017/10/04/service-worker/)
网络请求优化:
-
使用get进行请求,get会缓存请求,比起post,只发送一个tcp包,效率更好。
-
合并请求数量,减少http请求次数,节省网络请求时间。
接口合并(一个页面需要多个并行或串行的接口实属正常,网络不好的情况下,最好的办法就是通过接口合并的方式提高接口访问速度)。
- 多次请求和关闭会造成服务了压力,浏览器对每次请求的数量都有限制,一般是每次只能3次左右,合并请求将加快速度。
浏览器支持http并行请求数量有限,所以合并资源文件,可以加快请求,减少延迟 下载一个100kb的js文件比下载4个25kb的js更快。
- 抛开无用cookie,减少带宽占用,http协议每次发送请求都会自动带上该域名及父级域名下的cookie
浏览器缓存
强缓存,协商缓存(根据相应的header内容来决定的)
浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存(cache-control和expires信息)
若命中直接从缓存中获取资源信息,包括缓存header信息;本次请求根本就不会与服务器进行通信
如果没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息(Lase-Modified/If-Modified-Since和Etag/If-Node-Match),由 服务器根据请求中的相关header信息来比对结果是否协商缓存命中;
若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取,否则返回最新的资源内容。
缓存参考文章
https://juejin.im/post/5b3c87386fb9a04f9a5cb037
页面渲染速度优化(用户体验优化)
- css放在顶部,优先渲染。
- js放在底部,避免堵塞,减少白屏时间和首页渲染时间。
- 减少DOM数量,减少重排重绘。
- Virtual Dom。
- 预加载和懒加载。
- 骨架屏。
避免JS堵塞
使用async和defer,async不支持ie9,所以首推荐使用defer,如果使用defer或async请将script标签放到head标签中,以便让浏览器更早地发现资源并在后台线程中解析并加载JS
重排重绘
-
重排(reflow):渲染层内的元素布局发生修改,都会导致页面重新排列,比如窗口的尺寸发生变化,删除或添加DOM元素,修改了影响元素盒子大小的css属性(width,height,padding)
-
重绘(repain):所以对元素的视觉表现属性的修改,都会引发重绘
不管是重排还是重绘,都会堵塞浏览器。要提高网页性能,就要降低重排和重绘的频率和成本,尽可能少的触发重新渲染。
重排是CPU处理,重绘是GPU处理,CPU的处理效率远不及GPU,并且重排一定会引发重绘,而重绘不一定会引发重排
避免重排重绘:
css复用class去批量操作元素样式
图片在渲染前指定大小:因为img元素是内联元素,所以在加载图片后会改变宽高,严重的情况会导致整个页面重排,所以最后砸渲染前就指定其大小,或者让其脱离文档流
Virtual Dom
Virtual Dom使用高效的diff算法,避免对整棵DOM树进行变更,而是进行针对性的视图变更,将效率做到最优化。
步骤:
1.生成Virtual Dom树
2.对比两颗树的差异
比较两颗DOM树的差异是Virtual Dom算法最核心的部分,这也是我们常说的Virtual Dom的diff算法,但在比较的过程中,我们只比较同级的节点,非同级的节点不再我们的比较范围内,这样既可以满足我们的需求,又可以简化算法实现
比较树的差异,首先是对树进行遍历,常用的又两种遍历算法,分别是深度优先遍历和广度优先遍历,一般的diff算法中都采用的是深度优先遍历。
对新旧两颗树进行一次深度优先的变量,这样每个节点都会唯一的标记。在遍历的时候,每遍历到一个节点,就把该节点和新的树的同一个位置的节点进行对比,如果有差异的话就记录到一个对象里面。
在差异对象中记录了有改变的节点,每一个发生改变的内容也不尽相同,但也是有迹可循,常见的差异包括四种,分别是: 替换节点
增加/删除子节点
修改节点属性
改变文本内容
所以在记录差异的时候要根据不同的差异类型,记录不同的内容。
3.更新视图
在第二步得到整颗树的差异之后,就可以根据这些差异的不同类型,对DOM进行针对性的更新。与四中差异类型相对应的,是更新视图时具体的更新方法,分别是:
replaceChild()
appendChild()/removeChild()
setAttribute()/removeAttribute()
textContent
服务器优化
- 使用内容分发网络CDN 客户端可以通过最佳的网络链路加载静态资源。
- 开启Gzip压缩文件内容。
- 为文件头指定expires和cache-control。
- 对于静态内容,设置文件头过期事件,expires的值为永不过时(never expire)。
- 对于动态内容,使用恰当的cache-control文件头来帮助浏览器进行有条件的请求。
- 升级到HTTPS,才能开启http2和PWA功能。
Gzip压缩
不要对图片文件进行Gzip压缩,对图片进行压缩不但会占用后台大量资源,压缩效果其实并不可观,可以 说”弊大于利”,请在gzip_types把图片相关项去掉。
CDN(内容分发网络)
用户和服务器之间距离越远,经过的路由器越多,延迟也就越高。 CDN系统会遵循Cache-Control和Expires HTTP头标准对改请求返回的内容进行缓存,便于后面的请求不再回源,起到加速功能。
HTTPS VS HTTP
我们对HTTP和HTTPS常规的理解就是,HTTPS比HTTP多了一层SSL(安全套接层),SSL需要对数据进行加密和解密,http使用tcp三次握手建立连接,客户端和服务器端需要交换3个包。
https除了tcp三个包,还要加上ssl握手的9个包,所以一共是12个包。
所以http比https效率更高,https更安全
但是(此处是重点)
升级到https后,服务器可以开启http2.0版本,对比http1.x性能和缓存各方面要更好,还有其他新特性, 可以启动service work功能,更好的进行离线缓存,更好的离线体验。
HTTPS证书可以免费申请,阿里云跟腾讯云都可以申请,按照文档指示进行申请下载,然后将下载的证书上传到服务器,配置服务器的内容,就可以开启https、http2.0、service work等功能了。
HTTP2新特性
1.新的二进制格式
http1.x解析的是基于文本,基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性, 要做到健壮性考虑的是场景必然很多,二进制则不同,只认0和1的组合。 基于这种考虑http2.0的协议解析决 定采用二进制合适,实现方便且健状。
2.多路复用
即连接共享,每一个request都是用作连接共享机制的。 一个request对应一个id,这样一个连接上可以有多个request, 每个连接的request可以随机的混杂在一起,接收方可以根据request的id将request再归属到各自不同的服务器请求里。
3.header压缩
http1.x的header带有大量信息,而且每次都要重复发送,http2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,即避免了重复header的传输,又减小了需要传输的大小。
4.服务器推送 server push
是http2协议里面,唯一一个需要开发者自己配置的功能吗,其他功能都是服务器和浏览器自动实现,不需要开发者担心 概念:还没有收到浏览器请求,服务器就把各种资源推送给浏览器 比如:浏览器只请求了index.html,但是服务器把index.html,style.css,example.png全部发送给浏览器。这样的话,只需要一轮http通信,浏览器就得到了全部资源,提高了性能.
代码优化
流程控制
- 避免使用for…in(它能枚举到原型,所以很慢)
- 使用Map表代替大量的if-else和switch会提升性能和代码可阅读和维护性。
-
函数的防抖节流
-
事件委托的优点
1.减少内存消耗
有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候相应一个事件:
如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的,效率上需要消耗很多性能;
因此,比较好的方法就是把这个点击事件绑定到他的父层,也就是ul上,然后再执行事件的时候再去匹配目标元素
所以事件委托可以减少大量的内存小号,节约效率
2.动态绑定事件
事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的
所以使用事件在动态绑定事件的情况下是可以减少很多重复工作的。
- hidden
不管怎样,你是否曾经为了隐藏某个元素而使用过myElement.style.display = ‘none‘这种方法呢?如果是的话,请别再这么做了!只需要调用myElement.hidden = true即可实现元素隐藏的功能。
效率优化
-
易拓展,易维护,易维护的代码(函数式编程),快速定位Bug。
flow静态类型检查,ESLint
模块化变化才能,封装共用的组件
-
引入Webpack,Rollup,Parcel等自动化构建工具
Webpack构建优化
区分开发环境和生产环境,自动提取公共代码,压缩代码,开启热更新、自动保存刷新功能等。
使用ES6,引入babel-loader,并开启缓存,解决兼容性。
引入Less,Sass等CSS预处理器,提高编码效率和浏览器兼容性。
线上环境优化
错误监控
sentry(国外开源的错误监控,有线上环境也可以自行部署)
自动化构建、持续集成
Travis CI(对Github支持很友好)
工具
网络传输性能检测工具 –page Speed(Chrome下载拓展插件Page Speed) 它会对测试网站的性能瓶颈提出完整的建议,我们可以根据它的提示进行优化工作。
以上是关于前端性能优化的主要内容,如果未能解决你的问题,请参考以下文章