前端性能优化

130 阅读6分钟

性能优化是高级前端开发绕不开的槛。

虽然性能优化的方法可以罗列几十条,但是我们需要遵守的或者常用的十几条也就够了。性能优化可以提升网站性能,但是配置麻烦,并且带来的条条框框太多,一味的追求的性能优化,可能带来代码阅读和维护的成本;并且,某些细枝末节的性能优化方法并不能明显的带来性能提升,这时就有些得不偿失了。因此,本文章只讨论实际情况中常用的,性能提升明显的十几种方法

1.减少HTTP请求

http请求中,真正的下载时间很少,时间主要花费在了等待、连接、握手等事件上了,一个大文件和一个小文件的请求时间相差无几。因此,减少http请求数量可以明显的加快加载速度。 方法:

  1. 合并图片;
  2. 压缩css样式表和js脚本;
  3. 去掉不必要的请求。

2.使用服务端渲染

  • 客户端渲染:获取HTML文件,根据需要下载js文件,运行文件生成DOM,再渲染。
  • 服务端渲染:服务端返回HTML文件,客户端只需解析HTML。
  • 优点:首屏渲染快,SEO好。
  • 缺点:配置麻烦,增加了服务器的计算压力

3.静态资源使用CDN

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

4.将css文件放在文件头部,js文件放在底部

  • css执行会阻塞渲染,阻止js执行
  • js加载和执行会阻塞HTML解析,阻止CSSOM构建

如果这些css、js标签放在head标签里,并且需要加载和解析很久的话,那么页面旧空白了。所以js文件要放在底部(不阻止DOM解析,但会阻塞渲染),等HTML解析晚了再加载js文件,尽早向用户呈现页面的内容。

那为什么css文件还要放在头部呢?

因为现加载HTML再加载css,会让用户第一时间看见的页面是没有样式的,为了避免这种情况,就要将css文件放在头部了。

另外,js文件也不是不可以放在头部,只要给script标签加上defer属性就可以了,异步下载,延迟执行

5.图片优化

  • 将图标制成字体图标,生成的文件特别小;
  • 尽可能地使用PNG图片,相对体积较小;
  • 雪碧图,将多个图片合并成一个大图片,避免多次请求;
  • 图片的懒加载

6.善用缓存,不重复加载相同的资源

为了避免用户每次访问网站都得请求文件,我们可以通过添加Expires或max-age来控制这一行为。Expires设置了一个时间,只要在这个时间之前,浏览器都不会请求文件,而是直接使用缓存。而max-age是一个相对时间。

不过这样会产生一个问题,当文件更新了怎么办?怎么通知浏览器重新请求文件?

可以通过更新页面中引用的资源链接地址,让浏览器主动放弃缓存,加载新资源

7.压缩文件

压缩文件可以减少文件下载时间,让用户体验性更好。

在 webpack 可以使用如下插件进行压缩:

  • JavaScript:UglifyPlugin
  • CSS :MiniCssExtractPlugin
  • HTML:HtmlWebpackPlugin

其实,我们还可以做得更好。那就是使用 gzip 压缩。可以通过向 HTTP 请求头中的 Accept-Encoding 头添加 gzip 标识来开启这一功能。当然,服务器也得支持这一功能。

gzip 是目前最流行和最有效的压缩方法。举个例子,我用 Vue 开发的项目构建后生成的 app.js 文件大小为 1.4MB,使用 gzip 压缩后只有 573KB,体积减少了将近 60%。

8.通过webpack按需加载代码

懒加载或者按需加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。

9.减少重绘重排

浏览器渲染过程

  1. 解析HTML生成DOM树。
  2. 解析CSS生成CSSOM规则树。
  3. 将DOM树与CSSOM规则树合并在一起生成渲染树。
  4. 遍历渲染树开始布局,计算每个节点的位置大小信息。
  5. 将渲染树每个节点绘制到屏幕。

重排

当改变 DOM 元素位置或大小时,会导致浏览器重新生成渲染树,这个过程叫重排。

重绘

当重新生成渲染树后,就要将渲染树每个节点绘制到屏幕,这个过程叫重绘。不是所有的动作都会导致重排,例如改变字体颜色,只会导致重绘。记住,重排会导致重绘,重绘不会导致重排 。

重排和重绘这两个操作都是非常昂贵的,因为 JavaScript 引擎线程与 GUI 渲染线程是互斥,它们同时只能一个在工作。

什么操作会导致重排?

  • 添加或删除可见的 DOM 元素
  • 元素位置改变
  • 元素尺寸改变
  • 内容改变
  • 浏览器窗口尺寸改变

如何减少重排重绘?

  • 用 JavaScript 修改样式时,最好不要直接写样式,而是替换 class 来改变样式。
  • 如果要对 DOM 元素执行一系列操作,可以将 DOM 元素脱离文档流,修改完成后,再将它带回文档。推荐使用隐藏元素(display:none)或文档碎片(DocumentFragement),都能很好的实现这个方案。

10.使用事件委托

事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。所有用到按钮的事件(多数鼠标事件和键盘事件)都适合采用事件委托技术, 使用事件委托可以节省内存。

11.css方面的优化

  • 降低 CSS 选择器的复杂性;
  • 使用 flexbox 而不是较早的布局模型(比如定位、浮动);
  • 使用transform和opacity属性来实现动画(不会触发重排与重绘)

12.优化js执行

  • 使用requestAnimationFrame来实现视觉变化;
  • 使用IntersectionObserver来监听某元素是否进入了视口;
  • 降低js代码算法复杂度