大前端性能优化总结

原文链接: https://juejin.im/post/5b57502df265da0f61320d76

客户端优化

静态资源优化

  • 使用构建工具对HTML,CSS,JS压缩,删除生产环境下的无用代码(比如注释,打印信息等)。

  • 提取公共资源,减少代码体积。

  • 外链CSS和JS文件,外链的文件可以放到CDN,服务器和浏览器会进行缓存。

  • 使用雪碧图,减少http请求数。

    自动生成雪碧图:www.toptal.com/developers/…

  • 使用字体图标iconfont:

    www.iconfont.cn/

  • 图片使用webp格式

    www.upyun.com/webp

  • 缓存(Service Worker)

    github.com/youngwind/b…

    fed.renren.com/2017/10/04/…

网络请求优化:

  • 使用get进行请求,get会缓存请求,比起post,只发送一个tcp包,效率更好。

  • 合并请求数量,减少http请求次数,节省网络请求时间。

接口合并(一个页面需要多个并行或串行的接口实属正常,网络不好的情况下,最好的办法就是通过接口合并的方式提高接口访问速度)。

  • 多次请求和关闭会造成服务了压力,浏览器对每次请求的数量都有限制,一般是每次只能3次左右,合并请求将加快速度。

浏览器支持http并行请求数量有限,所以合并资源文件,可以加快请求,减少延迟 下载一个100kb的js文件比下载4个25kb的js更快。

  • 抛开无用cookie,减少带宽占用,http协议每次发送请求都会自动带上该域名及父级域名下的cookie

浏览器缓存

强缓存,协商缓存(根据相应的header内容来决定的)

浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存(cache-controlexpires信息)

若命中直接从缓存中获取资源信息,包括缓存header信息;本次请求根本就不会与服务器进行通信

如果没有命中强缓存,浏览器会发送请求到服务器,请求会携带第一次请求返回的有关缓存的header字段信息(Lase-Modified/If-Modified-SinceEtag/If-Node-Match),由 服务器根据请求中的相关header信息来比对结果是否协商缓存命中;

若命中,则服务器返回新的响应header信息更新缓存中的对应header信息,但是并不返回资源内容,它会告知浏览器可以直接从缓存获取,否则返回最新的资源内容。

缓存参考文章

juejin.im/post/5b3c87…

页面渲染速度优化(用户体验优化)

  • css放在顶部,优先渲染。
  • js放在底部,避免堵塞,减少白屏时间和首页渲染时间。
  • 减少DOM数量,减少重排重绘。
  • Virtual Dom。
  • 预加载和懒加载。
  • 骨架屏。

避免JS堵塞

使用async和defer,async不支持ie9,所以首推荐使用defer,如果使用defer或async请将script标签放到head标签中,以便让浏览器更早地发现资源并在后台线程中解析并加载JS

重排重绘

  1. 重排(reflow):渲染层内的元素布局发生修改,都会导致页面重新排列,比如窗口的尺寸发生变化,删除或添加DOM元素,修改了影响元素盒子大小的css属性(width,height,padding)

  2. 重绘(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会提升性能和代码可阅读和维护性。

  • 函数的防抖节流

    justclear.github.io/throttle-an…

  • 事件委托的有点

    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(国外开源的错误监控,有线上环境也可以自行部署)

sentry官网

sentry跟Vue搭配

自动化构建、持续集成

Travis CI(对Github支持很友好)

阮一峰Travis CI教程

你可能感兴趣的:(前端笔记)