性能优化常见问题

雅虎军规

在前端性能优化中,雅虎军规起到了至关重要的作用,大多数情况下我们可以直接参考雅虎军规。这里不做过多笔记了,参考链接如下:

雅虎军规中文版

测试网速

拿到用户网速可以做很多事情,如在用户网速不好的情况下可返回一倍图等。

获取用户网速的办法:

  • navigator.connection (不准,不推荐使用),Navigator

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    const connection = navigator.connection
    // 获取当前网络信息类型
    let type = connection.effectiveType // 3g
    // 网络信号的改变
    connection.onchange = function (e) {
    console.log(connection.effectiveType);
    }
    console.log('是否在线', navigator.onLine)
    console.log('网速', connection.downlink, 'MB/s')
    window.addEventListener("online", () => {
    console.log('网络已连接')
    });
    window.addEventListener("offline", () => {
    console.log('网络已断开')
    });
  • 在服务器放个 1KB 的图片 看返回时间差

  • 多普勒测速: 分五次请求,计算公式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    // 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(TCP) +RTT(一次传输)
    // T2 = New Connection(TCP) +RTT(一次传输)
    // T3 = RTT(一次传输)
    // 10k/(t4-t3)~TCP bandwidth
    // (40k-10k)/(t5-t4)~TCP bandwidth

css和js阻塞问题

  1. script标签放在底部会影响dom渲染吗?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>script虽然放在了页面底部 渲染依旧等待</title>
    </head>
    <body>
    <h1>标题</h1>
    <script type="text/javascript">
    prompt('等待');
    </script>
    </body>
    </html>

    这里会先看见弹框再渲染页面,所以答案是会,script放在底部是不会影响dom解析而不是不会影响渲染

  2. css加载会影响dom的渲染吗?

    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
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <style>
    h1 {
    color: red !important;
    }
    </style>
    <script>
    function h() {
    console.log(document.querySelectorAll('h1'));
    }
    setTimeout(h, 0);
    </script>
    <link
    href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.4.0/css/bootstrap.css"
    rel="stylesheet"
    />
    </head>
    <body>
    <h1>哈哈哈</h1>
    <!-- CSS加载会影响DOM树的渲染么? -->
    </body>
    </html>

    这里引入了一个远程的css,在浏览器开发者工具中把网速调的很慢时,css加载完成之前浏览器窗口内是不会看见h1标签的,但是我们的js却可以拿到h1标签,这说明CSS加载不会影响Dom树的解析 但是影响DOM树的渲染

  3. css加载会影响js执行么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CSS加载会阻塞后面JS 语句执行</title>
<script>
console.log('before css');
var startDate = new Date();
</script>
<link
href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.4.0/css/bootstrap.css"
rel="stylesheet"
/>
</head>
<body>
<h1>demo1标题</h1>
<script>
console.log('after css');
var endDate = new Date();
console.log(endDate - startDate);
</script>
</body>
</html>

跟问题2一样,当把网速调的很慢时,下面的js得等到css加载完成才会执行,看见after css,(js中可能会操作css)

  1. css加载会影响domready么?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script>
    document.addEventListener('DOMContentLoaded', function () {
    console.log('DOMContentLoaded');
    });
    </script>
    <link
    href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.4.0/css/bootstrap.css"
    rel="stylesheet"
    />
    </head>
    <body>
    <h1>demo1标题</h1>
    <script>
    console.log('到我没');
    </script>
    <!---->
    <!---->
    </body>
    </html>
    当我们注释下面的script时,控制台会输出DOMContentLoaded,否则不会。结论:如果页面中同时存在了CSS和js,并且存在Js 且在CSS后面 DOMContentLoaded就会在CSS加载后才能执行;其他情况下 DOMContentLoaded不会等待CSS加载 他也不会等待图片、视频资源加载。

重排(回流)和重绘

  • 什么是重排(回流)

    当render tree中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建。这就称为重排(reflow)。每个页面至少需要一次重排,就是在页面第一次加载的时候,这时候是一定会发生重排的,因为要构建render tree。

    重排 盒模型改变必定会重排,重排一定会引起重绘

    • 添加/删除元素
    • 内容发生改变(文字数量或图片大小等等)
    • display:none
    • 移动元素位置
    • 修改浏览器大小,字体大小

    一些读取操作也可能引起重排

    • offset(Top|Left|Width|Height)
    • scroll(Top|Left|Width|Height)
    • client(Top|Left|Width|Height)
    • getComputedStyle()
  • 什么是重绘

    在重排的时候,浏览器会使渲染树中受到影响的部分失效,并重新构造这部分渲染树,完成重排后,浏览器会重新绘制受影响的部分到屏幕中,该过程成为重绘。

    重绘的触发: 任何对元素样式,如 color,background-color 等属性的改变,JS和CSS都会引起重绘。

浏览器会维护1个队列,把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。但是在用JS操作DOM时,当去查询这些属性时,浏览器就会强制刷新队列。因为如果不立即执行队列中的任务,有可能得到的结果是错误的。相当于你强制打断了浏览器的优化流程,引起了重排。也就是上面说的为什么读取操作可能引起重排。

requestAnimationFrame

执行动画,可以使用 requestAnimationFrame 要求浏览器在下次重绘之前调用指定的回调函数更新动画,避免多余的操作。

fastdom库

fastdom是一个优秀的库,可以帮助我们批量访问DOM,避免了不必要的文档重排,并极大地提高了布局性能。

查看评论