前端性能优化

337 阅读5分钟

浏览器加载过程

网络请求

graph TD
A[输入URL] --> B(强缓存)
B --> |no| C(DNS缓存)
B --> |yes| O
C --> |no: DNS协议| D(以太网协议)
C --> |yes| D
D --> E(IP协议)
E --> F(TCP协议)
F --> G(HTTP连接)
G --> H(Nginx缓存)
H --> |no: 负载均衡| I(Node集群/中间层)
H --> |yes| P
I --> J(协商缓存)
J --> |no| K(同构)
J --> |yes| O
K --> N(应用服务器RESTFUL接口/处理业务)
N --> M(数据库读写)
M -.-> P
O(本地缓存)
P[返回响应]

浏览器渲染

graph TD
A(浏览器解析HTML)
A --> B(HTML)
A --> C(CSS)
A --> D(JS)
B --> BA(DOM)
C --> CA(CSSOM)
CA -.-> E(构建渲染树)
E --> F(布局)
F --> G(绘制)
G --> H(DOMContentLoaded)
H --> I(onLoad)

网络优化

离线缓存

Application Cache(Manifest)

HTML5缓存技术。html标签中添加manifest属性,属性值为manifest文件的路径。manifest文件是文本文件,它会告知浏览器需要缓存的内容以及不需要缓存的内容。

Service workers

是 Web Worker 的一种,相当于代理服务器,可以拦截请求,意味着可以在离线环境下响应请求。

  • 基于 Https;
  • 每个 Service Workers 只会处理自己作用域下的请求;
  • 它不能直接操作 DOM,通过 postMessage 与主窗口通信。

强缓存

  • Expires 是HTTP/1.0提出的表示资源过期时间的响应头,它描述的是一个绝对时间,由服务器返回。Expires 受限于本地时间,如果修改了本地时间,可能会造成缓存失效。如 Expires: Wed, 11 May 2018 07:20:00 GMT。
  • Cache-Control 出现于HTTP/1.1,表示的是相对时间,优先级高于 Expires。如 Cache-Control: max-age=315360000。

DNS缓存

减少DNS查询和解析域名,尽量使用同域名。

HTTP协议

HTTPS:

  • 二进制协议解析
  • 多请求、响应
  • 可以控制数据流优先级,标记、取消数据流
  • 头信息压缩、重用
  • 服务器推送

协商缓存

  • Last-Modified(响应头)与 If-Modified-Since(请求头)表示本地文件最后修改日期。
  • ETag(响应头)与 If-None-Match(请求头)表示资源的唯一标识。

同构

  • SPA:单页面应用,前端渲染和交互。
  • 直出:服务端渲染,纯后端渲染。
  • 同构:后端渲染,前端交互。服务端直出和客户端渲染组合,结合两者的优势并避免两者的不足。代码部署在后端,代码同时运行在服务端和客户端。与SPA相比,SSR返回的数据多了个静态页面(字符串形式)。

同构的好处

  • SEO
  • Node直出,首屏渲染速度快
  • 前后端共享某些代码

其他

  • 减少http请求
  • 避免重定向
  • 减小资源大小:如Webpack压缩合并、打包、缓存、懒加载、去重等
  • 使用CDN
  • Ajax缓存

浏览器渲染优化

浏览器渲染过程

  1. 浏览器解析HTML/XHTML/SVG生成DOM树(DOM Tree)
  2. 浏览器解析CSS生成CSS规则树(CSS Rule Tree / CSSOM)
  3. 在生成DOM树过程中,如果遇到JavaScript,浏览器暂停构建DOM,先下载和构建CSSOM(因为JS可以修改CSSOM),然后再执行JS,最后继续构建DOM。JS通过DOM API和CSSOM API来操作DOM Tree和CSS Rule Tree
  4. 浏览器引擎通过DOM树CSS规则树来构造渲染树(Rendering Tree)。 或 display: none; 不会出现在渲染树中
  5. 浏览器根据渲染树布局/回流/重排(Flow),布局完成后绘制/重绘(Paint)。回流会引发重绘重绘不一定引发回流

HTML

  • 优化加载顺序
  • 异步加载css、js(如:使用async、defer)
  • 外链css、js,利用浏览器的缓存机制
  • 避免嵌套
  • 避免空标签、空格、注释,避免空的src、href属性,删除默认属性
  • 语义化:有利爬虫、开发可读、屏读

CSS

  • 避免嵌套
  • 选择器
  • 属性:重排(如:改变外边距)、重绘(如:页面滚动时禁用hover事件)、盒模型顺序
  • 启用GPU硬件加速

JS

API Time complexity
  • indexOf() O(n)
  • hasOwnProperty() O(1)
  • (new Set()).has() O(1)
垃圾回收

内存泄漏:不再用到的内存,没有及时释放:

  • 作用域未释放
  • 较长生命周期的键值对象缓存、多余的全局变量
  • 无效的DOM引用
  • 事件监听未清除
  • 定时器未清除

内存泄漏优化:

  • 避免并解除闭包
  • 避免使用较长生命周期的键值对象缓存而是拆分成多个、清空变量
  • 解除引用
  • 清除监听器
  • 清除定时器
  • WeakSet 和 WeakMap 对于值的引用都不计入垃圾回收机制
  • Node 中使用 stream 或 buffer 来操作大文件,不会受 Node 内存限制
  • 使用 redis 等外部工具缓存数据
框架

React

  1. 不要进行DOM节点跨层级的操作,可以通过CSS隐藏显示节点,避免嵌套
  2. 组件保持同类型并结合 shouldComponentUpdate()
  3. 唯一key
  4. 拆分组件
  5. bind在constructor中绑定,不要在使用时绑定
  6. 组件中箭头函数对于组件来说每次绑定的都是新的函数,从而引发重新渲染
  7. 默认属性的值要放在变量中缓存
  8. 无状态组件
  9. 继承 React.PureComponent生成组件,render前进行浅比较,从而决定是否更新组件
  10. 官方或第三方库

Redux

  1. store扁平化,避免嵌套
  2. store范式化,尽可能少的数据
  3. 将和redux有连接的多个组件拆分成多个 connect 的单个组件
  4. mapStateToProps会将组件的props作为第二个参数,在此做比较使传入组件的props为boolean
其他
  • 尾调用,尾递归
  • DocumentFragment
  • 防抖、节流
  • localStorage,sessionStorage
  • Web worker独立线程

首屏渲染

白屏时间 首屏时间
  • 白屏时间是指浏览器从响应用户输入网址地址,到浏览器开始出现第一个元素的时间,影响因素是网络、服务端性能、前端页面结构设计。new Date() - performance.timing.navigationStart
  • 首屏时间是指浏览器从响应用户输入网络地址,到首屏内容渲染完成的时间,影响因素是白屏时间、资源下载执行时间。window.onload => new Date() - performance.timing.navigationStart