# 性能优化篇(一)

# 为什么要进行性能优化?

  • 57%的用户更在乎网⻚在3秒内是否完成加载。

  • 52%的在线用户认为网⻚打开速度影响到他们对网站的忠实度。

  • 每慢1秒造成⻚面 PV 降低11%,用户满意度也随之降低降低16%。

  • 近半数移动用户因为在10秒内仍未打开⻚面从而放弃。

    性能优化白皮书

# 性能优化学徒工

  • 雅⻁军规
  • 缓存策略
  • 网站协议
  • 小字为先

# 雅⻁军规践行

/optimization/yahu.png

  • 浏览器正常并发script请求5个左右,大小100k左右,压缩后30k
  • CDN,使用CDN是因为不会携带多余的cookie。使用多个CDN,解决浏览器对同一个域名的并发。

# 缓存的优先级

cache-control--expires--etag--last-modified

etag / if-none-match

这也是一组请求/相应头 响应头: etag: "D5FC8B85A045FF720547BC36FC872550" 请求头: if-none-match: "D5FC8B85A045FF720547BC36FC872550"

原理类似,服务器端返回资源时,如果头部带上了 etag,那么资源下 次请求时就会把值加入到请求头 if-none-match 中,服务器可以对比 这个值,确定资源是否发生变化,如果没有发生变化,则返回 304。

last-modified / if-modified-since

这是一组请求/相应头

响应头:

* last-modified: Wed, 16 May 2018 02:57:16 GMT 01 请求头:

if-modified-since: Wed, 16 May 2018 05:55:38 GMT

服务器端返回资源时,如果头部带上了 last-modified,那么 资源下次请求时就会把值加入到请求头 if-modified-since 中,服务器可以对比这个值,确定资源是否发生变化,如果 没有发生变化,则返回 304。

expires

* expires: Thu, 16 May 2019 03:05:59 GMT 在 http 头中设置一个过期时间,在这个过期时间之前,浏览器的请求都不会发出,而是

自动从缓存中读取文件,除非缓存被清空,或者强制刷新。缺陷在于,服务器时间和用 户端时间可能存在不一致,所以 HTTP/1.1 加入了 cache-control 头来改进这个问题。

cache-control

HTTP强缓

设置过期的时间⻓度(秒),在这个时间范围内,浏览器请求都会直 接读缓存。当 expires 和 cache-control 都存在时,cache-control 的 优先级更高。

举个例子:

  1. 常用的库 jquery http强缓存,对版本的要求不是很严格,只需要跟服务器校验
  2. 业务代码 本地缓存 MD5变化非常频繁 http->缓存失败
    1. localstorage 5M
    2. web SQL 50M (前端ORM存储方案 库localForage
    3. 启动文件:查看本地是否有这个缓存的js
    4. 有 :先判断是否过期
      1. 已过期:删除两个key的值,拉取js文件 请求etag,请求js,增加两个key code
      2. 没过期: 直接取缓存的代码 (eval、addScript)
    5. 没有: 直接拉取js,请求js,增加两个key code

# 网站协议

浏览器请求//xx.cn/a.js-->解析域名—>HTTP连接—>服务器处理文件—>返回数据-->浏览器解析、渲染文件。

Keep-Alive解决的核心问 题就在此,一定时间内,同一域名多次请求数据,只建立一次HTTP请求,其他请求可复用每一次建立的连接通道,以达到提高请求 效率的问题。一定时间是可以配置的,HTTP1.1还是存在效率问题,第一个:串行的文件传输。第二个:连接数过多。HTTP/2对同一 域名下所有请求都是基于流,也就是说同一域名不管访问多少文件,也只建立一路连接。同样Apache的最大连接数为300,因为有了 这个新特性,最大的并发就可以提升到300,比原来提升了6倍!

# 多普勒测速

分五次请求,计算公式

  1. api?http1.0&t=1&size=0k
  2. api?http1.1&t=2&size=0k
  3. api?http1.1&t=3&size=0k
  4. api?http1.1&t=4&size=10k
  5. api?http1.1&t=5&size=40k
  • T1 = DNS+New Connection+RTT
  • T2 = New Connection+RTT
  • T3 = RTT
  • 10k/(t4-t3)~TCP bandwidth
  • (40k-10k)/(t5-t4)~TCP bandwidth

# 渲染中性能优化

  • 重绘影响
  • 如何规避
  • 重排影响
  • 高效渲染

# css是否会引起重排和重绘

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .box {
            width:100px;
            height: 100px;
            border: 1px solid #ccc;
            border-radius: 50%;
            position: absolute;
            animation: cicleBox 2s infinite;
        }

        @keyframes cicleBox {
            0% {
                /* top: 0;
                left: 0; */
                transform:translate(0,0);
            }
            25% {
                /* top: 0;
                left: 200px; */
                transform:translate(200px,0);
            }
            50% {
                /* top: 200px;
                left: 200px; */
                transform:translate(200px,200px);
            }
            75% {
                /* top: 200px;
                left: 0; */
                transform:translate(0,200px);
            }
        }
    </style>
</head>
<body>
    <div class="box"></div>
</body>
</html>
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  • 上述代码中 使用top和left值进行变化时,会进行重排和重绘。
  • 上述代码中 使用transform进行变化时,不会进行重排和重绘。
  • 实际使用例子参考淘宝官网轮播图

**结论:**css是否会引起重排和重绘,取决于代码的书写。

分析:

1. 网页的渲染流程
  	1. 浏览器的dom是分层的,网页是3D的。
  	2. 对DOM元素节点计算样式结果Recalculate Style样式重计算
  	3. 为每个节点生成图形位置Layout回流重排
  	4. 将每个节点绘制填充到图层中Paint
  	5. 图层作为纹理上传到GPU
  	6. Composite Layers 合成层把符合图层生成到页面
  	7. Composite Layers 做了什么?
       	1. 图层的绘制列表,准备好,主线程 commit 合成线程
       	2. 合成线程 viewport rt 划分图块
       	3. 生成位图   栅格化(光栅化) raster
       	4. 所有图块 GPU合成生成DarwQuad提交给浏览器渲染进程
       	5. viz组件  接收到DarwQuad 绘制到我们的屏幕上
2. 分层
  	1. 根元素,position分层,transform,半透明,css滤镜,canvas,video,overflow
  	2. GPU硬件加速:CSS3D,video,webgl,transform,will-change:transform
3. 重绘和重排(盒子动了必定重排)
  	1. offset,scroll,client,width 读取   会打断浏览器工作。造成重排。
  	2. 优化: requestAnimationFrame 下一帧去写(react利用了他:设置dom元素,读写分离)
  	3. cpu负责操作系统和程序和数据处理
  	4. gpu负责显示 数据处理 效率更高
  	5. fastdom控制读写分离的插件
  	6. csstriggers.com可查看是否引起重排重绘

1595815442160_87F5067C-6E6C-4665-999B-F65D74FFC08E


# css和js会阻塞页面解析渲染吗

  1. js不会影响Dom解析,会影响Dom渲染

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
      </head>
      <body>
        <h1>京程一灯</h1>
        <script>
          // DOM解析不影响 渲染依旧等待
          prompt('等待');
        </script>
      </body>
    </html>
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
  2. css不会影响Dom解析,会影响Dom渲染

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <style>
          h1 {
            color: red !important;
          }
        </style>
        <script>
          function h() {
            console.log(document.querySelectorAll('h1'));
          }
          setTimeout(h, 0);
        </script>
        <link
          rel="stylesheet"
          href="https://cdn.staticfile.org/twitter-bootstrap/5.0.0-alpha1/css/bootstrap-utilities.min.css"
        />
      </head>
      <body>
        <h1>
        		1.css 影响DOM渲染
            2.css 不会影响DOM解析
        </h1>
      </body>
    </html>
    
    
    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
    27
    28
    29
    30
  3. css加载会阻塞后面的js语句

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
        <style>
          h1 {
            color: red !important;
          }
        </style>
        <link
          rel="stylesheet"
          href="https://cdn.staticfile.org/twitter-bootstrap/5.0.0-alpha1/css/bootstrap-reboot.min.css"
        />
      </head>
      <body>
        <h1>京程一灯</h1>
        <script>
          console.log('css 加载会阻塞后面JS语句');
        </script>
      </body>
    </html>
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
  4. css会影响DOM ready吗?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            console.log('不会')
        })
    </script>
    <link rel="stylesheet" href="">
</head>
<body>
    <h1>不会</h1>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            console.log('会')
        })
    </script>
    <link rel="stylesheet" href="">
    <script>
				//任何内容
    </script>
</head>
<body>
    <h1></h1>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# ⻚面加载性能优化(Page Loading Performance Optimization)

# 基础知识

基础

1595840694580_1EDBF71B-7361-49A4-AE92-3337F2CF4D15

tti的库tti-polyfill

新增

1595840778135_97517B4B-05F4-45C3-930C-5B453FFC2327

概念

1595841967649_8D077769-C1FA-4B71-B30B-4C9318093ED1

1595842049356_6EE795A8-4684-44ED-995F-B2429638852C

1595842085720_2BDB15C5-3E5A-407A-B4CA-621E3C0BF3B9

1595842323296_4BB64B51-4264-475C-8F54-617F35552CF8

# 白屏

1595842482364_D2B83AF2-818D-47EB-B3F6-F9CB29B2DED6

1595842577621_4625F4DE-21DC-4BAC-B159-F12B46829B21

两个点:网略层和渲染层

1595842712996_29ECAD19-8480-4DD2-A704-2F9AE612EE26

VUE

1595842814139_CCF814F6-7AF5-4A3F-9FE8-E8E2B00DE7CB

1595842921185_44E5ED3A-C03C-451B-BE8A-D7F1A35FE391

<script>
  let t = performance.timing;
  console.log(
    'DNS查询耗时 :' + (t.domainLookupEnd - t.domainLookupStart).toFixed(0)
  );
  console.log('TCP链接耗时 :' + (t.connectEnd - t.connectStart).toFixed(0));
  console.log(
    'request请求耗时 :' + (t.responseEnd - t.responseStart).toFixed(0)
  );
  console.log(
    '解析dom树耗时 :' + (t.domComplete - t.domInteractive).toFixed(0)
  );
  console.log('白屏时间 :' + (t.responseStart - t.navigationStart).toFixed(0));
  console.log(
    'domready时间 :' +
      (t.domContentLoadedEventEnd - t.navigationStart).toFixed(0)
  );
  console.log(
    'onload时间 :' + (t.loadEventEnd - t.navigationStart).toFixed(0)
  );

  if ((t = performance.memory)) {
    console.log(
      'js内存使用占比 :' +
        ((t.usedJSHeapSize / t.totalJSHeapSize) * 100).toFixed(2) +
        '%'
    );
  }
</script>

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
27
28
29
30

1595843002573_4C39A93E-2D83-4E40-81BA-5C19380BD342

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      body {
        background: gray;
      }
    </style>
  </head>
  <body>
    <div id="app">
      123
      <h1>京程一灯</h1>
      <script>
        performance.mark('memory');
      </script>
    </div>
    <script>
      // for(){
      // }
      const observer = new PerformanceObserver((list) => {
        for (const entry of list.getEntries()) {
          console.log(entry.name);
          console.log(entry.startTime);
          console.log(entry.duration);
        }
      });
      observer.observe({ entryTypes: ['paint', 'mark', 'longtask'] });
    </script>
  </body>
</html>


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
27
28
29
30
31
32
33
34
35
36

官方的库 vitals

https://www.npmjs.com/package/web-vitals新增模块的数据都能拿到

# 总结

1595843053531_F4BE88F4-0F30-4122-8A24-5957282F29AE

# 日志

请求img1*1的图后面跟参数

例如:1*1.png?fc=0.22........

  1. navigator.sendBeacon
  2. ajax
  3. fetch(优先级太高)