Skip to content

Latest commit

 

History

History
219 lines (146 loc) · 10.2 KB

2.md

File metadata and controls

219 lines (146 loc) · 10.2 KB

前端性能优化

前端性能优化建议

⚡题目:

❓ 前端相关的性能优化方案

优解 🔥

前端性能优化 24 条建议

减少 HTTP 请求

一个完整的 HTTP 请求需要经历 DNS 查找,TCP 握手,浏览器发出 HTTP 请求,服务器接收请求,服务器处理请求并发回响应,浏览器接收响应等过程。 下载数据的时间与数据大小的成正比。这就是为什么要建议将多个小文件合并为一个大文件,从而减少 HTTP 请求次数的原因。

使用 HTTP2

  • 解析速度快:服务器解析 HTTP1.1 的请求时,必须不断地读入字节,直到遇到分隔符 CRLF 为止。而解析 HTTP2 的请求就不用这么麻烦,因为 HTTP2 是基于帧的协议,每个帧都有表示帧长度的字段
  • 多路复用: HTTP1.1 如果要同时发起多个请求,就得建立多个 TCP 连接,因为一个 TCP 连接同时只能处理一个 HTTP1.1 的请求。 在 HTTP2 上,多个请求可以共用一个 TCP 连接,这称为多路复用。同一个请求和响应用一个流来表示,并有唯一的流 ID 来标识。 多个请求和响应在 TCP 连接中可以乱序发送,到达目的地后再通过流 ID 重新组建。
  • 首部压缩:HTTP/2 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送。
  • 优先级:HTTP2 可以对比较紧急的请求设置一个较高的优先级,服务器在收到这样的请求后,可以优先处理。
  • 流量控制: 流量控制可以对不同的流的流量进行精确控制。
  • 服务器推送:HTTP2 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。

服务端渲染 SSR

优点:首屏渲染快,SEO 好。 缺点:配置麻烦,增加了服务器的计算压力。

例:Vue SSR

客户端渲染

  • 访问客户端渲染的网站。
  • 服务器返回一个包含了引入资源语句和 <div id="app"></div> 的 HTML 文件。
  • 客户端通过 HTTP 向服务器请求资源,当必要的资源都加载完毕后,执行 new Vue() 开始实例化并渲染页面。

服务端渲染:

  • 访问服务端渲染的网站。
  • 服务器会查看当前路由组件需要哪些资源文件,然后将这些文件的内容填充到 HTML 文件。如果有 ajax 请求,就会执行它进行数据预取并填充到 HTML 文件里,最后返回这个 HTML 页面。
  • 当客户端接收到这个 HTML 页面时,可以马上就开始渲染页面。与此同时,页面也会加载资源,当必要的资源都加载完毕后,开始执行 new Vue() 开始实例化并接管页面。

静态资源CDN

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

CSS 放在文件头部,JavaScript 文件放在底部

CSS 和 JS 文件都会堵塞渲染(CSS 不会阻塞 DOM 解析)

  • css 放头部:避免页面渲染出现丑陋的样式布局,提前参与渲染
  • js 放尾部:避免加载JS导致页面空白时间过长

字体图标 iconfont 代替图片图标

字体图标就是将图标制作成一个字体,使用时就跟字体一样,可以设置属性,例如 font-size、color 等等,非常方便。 并且字体图标是矢量图,不会失真。还有一个优点是生成的文件特别小。

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

Expires 或 max-age

压缩文件

压缩文件可以减少文件下载时间,让用户体验性更好。 使用 gzip 压缩。可以通过向 HTTP 请求头中的 Accept-Encoding 头添加 gzip 标识来开启这一功能

图片优化

  • 图片延迟加载:在页面中,先不给图片设置路径,只有当图片出现在浏览器的可视区域时,才去加载真正的图片,这就是延迟加载
  • 响应式图片: 响应式图片的优点是浏览器能够根据屏幕大小自动加载合适的图片。
<!-- picture实现 -->
<picture>
  <source srcset="banner_w1000.jpg" media="(min-width: 801px)">
  <source srcset="banner_w800.jpg" media="(max-width: 800px)">
  <img src="banner_w800.jpg" alt="">
</picture>
/* @media 实现 */
@media (min-width: 769px) {
  .bg {
    background-image: url(bg1080.jpg);
  }
}
@media (max-width: 768px) {
  .bg {
    background-image: url(bg768.jpg);
  }
}
  • 调整图片大小: 用两张图片来实行优化。一开始,只加载缩略图,当用户悬停在图片上时,才加载大图。还有一种办法,即对大图进行延迟加载,在所有元素都加载完成后手动更改大图的 src 进行下载。
  • 降低图片质量: 100% 的质量和 90% 质量的通常看不出来区别,尤其是用来当背景图的时候
  • CSS3 效果代替图片: 代码大小通常是图片大小的几分之一甚至几十分之一。
  • 使用 webp 格式的图片

WebP 的优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,在 JPEG 和 PNG 上的转化效果都相当优秀、稳定和统一。

按需加载、提取第三库代码,减少 ES6 转为 ES5 的冗余代码

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

  • import() 动态引入
  • webpack4 的 splitChunk 插件 cacheGroups 选项
  • @babel/runtime 包就声明了所有需要用到的帮助函数,而 @babel/plugin-transform-runtime 的作用就是将所有需要 helper 函数的文件,从 @babel/runtime包 引进来, 避免每个文件都引用源码函数

减少重绘重排

重排: 当改变 DOM 元素位置或大小时,会导致浏览器重新生成渲染树。 重绘:当重新生成渲染树后,就要将渲染树每个节点绘制到屏幕

重排会导致重绘,重绘不会导致重排

浏览器渲染过程

  • 解析HTML生成DOM树。
  • 解析CSS生成CSSOM规则树。
  • 解析JS,操作 DOM 树和 CSSOM 规则树。
  • 将DOM树与CSSOM规则树合并在一起生成渲染树。
  • 遍历渲染树开始布局,计算每个节点的位置大小信息。
  • 浏览器将所有图层的数据发送给GPU,GPU将图层合成并显示在屏幕上

如何减少重排重绘?

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

事件委托

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

程序的局部性

一个编写良好的计算机程序常常具有良好的局部性,它们倾向于引用最近引用过的数据项附近的数据项,或者最近引用过的数据项本身,这种倾向性,被称为局部性原理。有良好局部性的程序比局部性差的程序运行得更快

  • 时间局部性:在一个具有良好时间局部性的程序中,被引用过一次的内存位置很可能在不远的将来被多次引用。
  • 空间局部性:在一个具有良好空间局部性的程序中,如果一个内存位置被引用了一次,那么程序很可能在不远的将来引用附近的一个内存位置

if-else 对比 switch

当判断条件数量越来越多时,越倾向于使用 switch 而不是 if-else。if-else 需要进行更多的判断,switch只需要进行一次判断。

查找表

使用map表获取

避免页面卡顿

60fps 与设备刷新率

  • requestAnimationFrame 来实现视觉变化
  • 对于一些长时间运行的 JavaScript,我们可以使用定时器进行切分,延迟执行

Web Workers

Web Worker 使用其他工作线程从而独立于主线程之外,它可以执行任务而不干扰用户界面。一个 worker 可以将消息发送到创建它的 JavaScript 代码, 通过将消息发送到该代码指定的事件处理程序(反之亦然)

位操作

JavaScript 中的数字都使用 IEEE-754 标准以 64 位格式存储。但是在位操作中,数字被转换为有符号的 32 位格式。即使需要转换,位操作也比其他数学运算和布尔操作快得多。

if (value % 2) {
  // 奇数
} else {
  // 偶数 
}
// 位操作
if (value & 1) {
  // 奇数
} else {
  // 偶数
}

~~10.12 // 10
~~10 // 10
~~'1.5' // 1
~~undefined // 0
~~null // 0

const a = 1
const b = 2
const c = 4
const options = a | b | c

不要覆盖原生方法

无论你的 JavaScript 代码如何优化,都比不上原生方法。因为原生方法是用低级语言写的(C/C++),并且被编译成机器码,成为浏览器的一部分。当原生方法可用时,尽量使用它们,特别是数学运算和 DOM 操作

降低 CSS 选择器的复杂性

  • 选择器越短越好
  • 尽量使用高优先级的选择器,例如 ID 和类选择器
  • 避免使用通配符 *

使用flexbox 布局

比起早期的布局方式来说有个优势,那就是性能比较好。

使用 transform 和 opacity 属性更改来实现动画

transforms 和 opacity 这两个属性更改不会触发重排与重绘,它们是可以由合成器(composite)单独处理的属性。

总结

合理使用规则,避免过度优化