前端页面渲染优化——performance工具分析优化

首先这是一个代码运行计算大量逻辑的优化。

(1)场景

  1. 当JS中存在大量数据的逻辑计算时
  2. 非静态资源优化
  3. 代码层次上的优化

(2)工具

Chrome Devtools 的performance, 在浏览器按下F12就可以找到。

(3)情况

当我们的页面在进行大量的数据逻辑运算时,我们的页面要等待数据计算完毕后才开始渲染加载完毕。首先这是因为页面渲染它是一个宏任务,在我们的task任务里面。主线程的main包含的task里也要进行js的计算,所以就造成了阻塞
前端页面渲染优化——performance工具分析优化

(4)我们创建一个页面,代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <title>未优化</title>
</head>
<body>
        
    <script>
        let t1, t2 = 0
        t1 = new Date() // 页面开始加载
        window.onload = (event) => {
            t2 = new Date() // 页面加载完毕
            console.log(`页面加载完毕用时: ${t2 - t1}ms`)
        }
    </script>
    <script>
        const a = () => {
            b()
        }

        const b = () => {
            let total = 0
            for(let i = 0; i < 10*10000*10000; i++) {
                total += i
            }
            console.log('1 : ', total)
        }

        a()
    </script>

    <script>
        const c = () => {
            d()
        }
        const d = () => {
            let total = 0
            for(let i = 0; i < 10*10000*10000; i++) {
                total += i
            }
            console.log('2 : ', total)
        }

        c()
    </script>
</body>
</html>

分析

  1. 页面加载时间:
// 控制台输出:
1 :  499999999067109000
2 :  499999999067109000
页面加载完毕用时: 3065ms
  1. 通过performance工具分析
    前端页面渲染优化——performance工具分析优化
    发现主线程的task宏任务里面 有两个long task。而正是这些long task 导致页面渲染时阻塞状态。

我们可以进去对应的源码查看:
前端页面渲染优化——performance工具分析优化

这些就是我们代码在运行的时间,我们找到了运行很长时间的代码,也就是long task 对应的 b函数d函数。现在我们只要消灭它们(long task)就可以让我们的页面快速加载完毕。

(5)开始优化

  1. 不放在主线程跑我们的函数,用worker工作者线程去跑
  2. 充分利用多线程的作用

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>优化后</title>
</head>
<body>

    <script>
        let t1, t2 = 0
        t1 = new Date() // 页面开始加载
        window.onload = (event) => {
            t2 = new Date() // 页面加载完毕
            console.log(`页面加载完毕用时: ${t2 - t1}ms`)
        }
    </script>

    <script>
        // 用worker线程优化 promise封装 postMessage本就使用异步的方式传递参数
        const runWorker = (url, num) => {
            return new Promise((resolve, reject) => {
                const worker = new Worker(url)
                worker.postMessage(num)
                worker.onmessage = (evt) => {
                    resolve(evt.data)
                }
                worker.onerror = reject
            })
            
        }
    </script>
    
    <script>
        const a = () => {
            b()
        }
        const b = () => {
            // 把b函数之前的数据逻辑的处理过程交给worker.js线程中的message事件去处理
            runWorker('./worker.js', 10*10000*10000).then(res => {
                console.log('res 01: ', res)
            }).catch(err => {
                console.log('err 01: ', err)
            })
        }
        a()
    </script>

    <script>
        const c = () => {
            d()
        }
        const d = () => {
            // 把d函数之前的数据逻辑的处理过程交给worker02.js线程中的message事件去处理
            runWorker('./worker02.js', 10*10000*10000).then(res => {
                console.log('res 02: ', res)
            }).catch(err => {
                console.log('err 02: ', err)
            })
        }
        c()
    </script>
</body>
</html>

worker.js和worker02.js负责写我们的计算逻辑

// 这里写b函数的处理逻辑

addEventListener('message', (evt) => {
    console.log(evt)
    let total = 0, num = evt.data
    for (let i = 0; i < num; i++) {
        total += i
    }
    console.log('worker.js 01 : ', total)
    // 最后可以把结果postMessage回去
    postMessage(total)
})

打开控制台查看:

  1. 页面加载后的时间:
页面加载完毕用时: 22ms
  1. 用performance工具分析

我们的main主线程的long task消失啦,它们都在worker线程上跑着,所以不影响我们的页面渲染啦。
前端页面渲染优化——performance工具分析优化

前端页面渲染优化——performance工具分析优化

总结

  1. 消除主线程Main的long task,从3000多毫秒降到了20多毫秒
  2. worker线程充分利用了多线程的作用
  3. 页面渲染解析HTML时,是一个宏任务
  4. 掌握performance常用的功能

源码在GitHub上:获取源码点这里

上一篇:[SAA + SAP] 21. SNS


下一篇:Performance Scaling Laws