# 性能优化

  • 抛开场景谈性能都是耍流氓!
  • 业务特性:读写频率、数据模型特点、用户特点 .etc
  • 目标
    • 提升用户体验
    • 提升执行效率
    • 减轻服务器压力
  • 限制
    • 安全性
    • 一致性
    • 可维护性
    • 成本

# https://web.dev (opens new window)

# w3c

interface PerformanceTiming {
  readonly attribute unsigned long long navigationStart;
  readonly attribute unsigned long long unloadEventStart;
  readonly attribute unsigned long long unloadEventEnd;
  readonly attribute unsigned long long redirectStart;
  readonly attribute unsigned long long redirectEnd;
  readonly attribute unsigned long long fetchStart;
  readonly attribute unsigned long long domainLookupStart;
  readonly attribute unsigned long long domainLookupEnd;
  readonly attribute unsigned long long connectStart;
  readonly attribute unsigned long long connectEnd;
  readonly attribute unsigned long long secureConnectionStart;
  readonly attribute unsigned long long requestStart;
  readonly attribute unsigned long long responseStart;
  readonly attribute unsigned long long responseEnd;
  readonly attribute unsigned long long domLoading;
  readonly attribute unsigned long long domInteractive;
  readonly attribute unsigned long long domContentLoadedEventStart;
  readonly attribute unsigned long long domContentLoadedEventEnd;
  readonly attribute unsigned long long domComplete;
  readonly attribute unsigned long long loadEventStart;
  readonly attribute unsigned long long loadEventEnd;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Processing Model

# 缓存

# 强缓存、协商缓存

优先级:cache-control > expires > etag > last-modified

name 类型 状态码
cache-control 强缓存 200 from memory / from disk
expires 强缓存 200 from memory / from disk
etag/if-none-match 协商缓存 304
last-modified/if-modified-since 协商缓存 304

# 本地缓存

  • cookie
  • sessionStorage
  • localStorage
  • IndexedDB
  • WebSQL

# worker

  • webWorker
  • serviceWorker
  • workbox(workbox-webpack-plugin)

TIP

前端代码缓存

serviceWorker缓存

    1. 注册serviceWorker
    1. 开启一个webWorker进程
    1. 激活serviceWorker
    1. 监听页面所有请求
    1. 当页面发起请求时触发监听器,有缓存则从缓存取,没有则网络请求,请求完成后缓存到Cache Storage
    1. 缓存策略同workbox给资源加上md5,可通过webpack打包生成md5 hash,通过hash判断资源是否需要更新

WARNING

serviceWorker拦截请求需在本地开发及https域名条件下

# 渲染指标

gpu.js

https://web.dev/metrics (opens new window)

web-vitals (opens new window)

name description
TTFP (opens new window) Time to First Byte 第一字节时间
FP First Paint 首次绘制
FCP (opens new window) First Contentful Paint 首次内容绘制
FMP First Meaningful Paint 首次有效绘制
LCP (opens new window) Largest Contentful Paint 最大内容绘制(替代FMP)
TTI (opens new window) Time to Interactive 可交互时间

PerformanceObserver 为我们提供的新功能是,能够在性能事件发生时订阅这些事件,并以异步方式响应事件。 此 API 取代旧的 PerformanceTiming (opens new window) 界面,后者通常需要执行轮询才能查看数据可用的时间。

// 使用 PerformanceObserver 获取 FP
const observerWithPromise = new Promise((resolve, reject) => {
  // return new PerformanceObserver((...rest) => {
  //   console.log('rest', rest)
  //   resolve(rest[0])
  // }).observe({
  //   entryTypes: ['paint'] // 注册 paint 性能事件
  // })
  return new PerformanceObserver(resolve).observe({
    entryTypes: ['paint'] // 注册 paint 性能事件
  })
}).then(entryList => { // 获得实体列表
  console.log('entries:', entryList.getEntries())
  return entryList.getEntries().find((entry) => {
    return entry.name === 'first-paint'
  })
}).then((entry) => {
  console.log('startTime:', entry.startTime)
})

// 使用 PerformanceObserver 获取 FCP
new Promise((resolve) => (
  new PerformanceObserver(resolve).observe({ entryTypes: ['paint'] })
))
.then((list) => (list.getEntries().find(entry => entry.name === 'first-contentful-paint')))
.then((entry) => console.log(entry.startTime))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Lighthouse (opens new window)

npm install -g lighthouse
# yarn global add lighthouse

lighthouse --help

lighthouse https://www.baidu.com --output-path=./lighthouse-results.json --output=json
1
2
3
4
5
6

Web Page Test (opens new window)

# 刷新SSR,切页SPA

# pjax

  • pushState + ajax = pjax (opens new window)
  • pjax 基于 jquery,代理指定元素点击行为并阻止其默认事件,在元素点击后通过 ajax 发送请求并携带自定义请求头(如:X-PJAX: true 等)将响应的 html 片段在其接管的区域内通过 pushState 替换,从而在 SSR 页面中实现 SPA 减少请求局部刷新的效果

# bigpipe

# Google AMP

  • AMP: Accelerated Mobile Pages
  • 场景:Mobile、资讯页面(非SPA)
  • 场景特点:
    • 机器性能
    • 浏览器性能
    • 网速受限
    • 非刚性需求
  • 权衡
    • 减少请求
    • 减少体积
    • 牺牲一部分UE
    • 牺牲一部分开发效率

# css-triggers

# 重排

# 导致原因

  • 读取某些CSS属性
    • clientWidth/clientHeight/clientLeft/clientTop
    • offsetWidth/offsetHeight/offsetLeft/offsetTop
    • scrollWidth/scrollHeight/scrollLeft/scrollTop
    • getBoundingClientRect()/getClientRects()
    • innerText/outerText
    • scrollIntoView()/scrollIntoViewIfNeeded()
    • scrollByLines()/scrollByPages()
    • focus()

# 解决方案

  • 使用transform代替top/left动画
  • DOM读写分离,尽量不要把读操作和写操作放在一个语句里面
    • 面对解耦代码,使用requestAnimationFrame达到读写分离
    • 使用 fastdom (opens new window) 进行优化,在每一帧,先将读操作批量运行,再批量运行写操作
  • 样式表越简单,重排和重绘越快
  • 重排和重绘的DOM元素层级越高,成本就越高
  • table元素的重排和重绘成本高于div
  • 统一改变样式
  • 缓存重排结果
  • 离线DOM Fragment/clone
  • 虚拟DOM
  • 必要的时候display: none不可见元素不影响重排重绘,visibility会影响重排

# 重绘

# 解决方案

  • 减少不必要的paint
    • gif图即使被其他layer盖住不可见,也可能导致paint,不需要时应将gif图的display属性设为none
    • 减少绘制区域,为引起大范围paint的元素生成独立的layer以减少paint的范围

# BFC (opens new window)

BFC是页面上一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也是。

  • BFC(Block Formatting Context)块格式化上下文
  • IFC(Inline Formatting Context)内联格式化上下文。IFC的line box(线框)高度由其包含的行内元素中的最高的实际高度计算而来(不受到垂直方向的padding/margin影响)。
  • FFC(Flex Formatting Context)自适应格式化上下文。display为flex/inline-flex的元素将会生成自适应容器。
  • GFC(GridLayout Formatting Context)网格格式化上下文。当为一个元素设置display为grid的时候,此元素将会获得一个独立的渲染区域,我们可以通过在网格容器(grid container)上定义网格定义行(grid definition rows)和网格定义列(grid definition columns)属性各在网格项目(grid item)上定义网格行(grid rows)和网格列(grid columns)为每一个网格项目(grid item)定义位置和空间。

# 生成BFC元素

  • html根元素
  • display为inline-block/table-cell/table-caption
  • float为left/right,不为none
  • position为absolute/fixed
  • overflow为auto/scroll/hidden

# 计算BFC的高度时,浮动元素也参与计算

# Margin collapsing

  • 盒子垂直方向的距离由margin决定,属于同一个BFC的两个相邻盒子的margin会发生重叠合并

css阻塞js执行,js阻塞DOM解析 有js时css会阻塞页面;无js时css不会阻塞页面

# BEM

getbem.com (opens new window)

# 参考

Last Updated: 10/29/2022, 10:22:28 AM