1

【前端调试】- 借助Performance分析并优化性能 - Leise

 1 year ago
source link: https://www.cnblogs.com/leise/p/17030932.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

【前端调试】- 借助Performance分析并优化性能

欢迎阅读本系列其他文章
【前端调试】- 更好的调试方式 VSCode Debugger
【前端调试】- 断点调试的正确打开方式

首先简单过一下Performance的使用,打开网页点击控制台Performance,录制5s的数据

image

其中 Main 这部分就是网页的主线程,也就是执行 Event Loop 的部分:

image

灰色就代表宏任务 task(这里带了红色是因为在 Performance 中宽度代表时间,超过 50ms 就被认为是 Long Task,会被标红。)
橙色:浏览器内部的 JS
蓝色:html parse
紫色:reflow、repaint
绿色:渲染
宽度代表了执行的时间,超过 50ms 就被任务是长任务,需要优化。
长度代表了调用栈深度,一般特别长的都是有递归在。

下面这段代码在Performance中会显示如下

  useEffect(() => {
    function a() {
      b();
    }
    function b() {
      let total = 0;
      for (let i = 0; i < 10 * 10000 * 10000; i++) {
        total += i;
      }
      console.log("b:", total);
    }

    a();
  });
1834753-20230106164520508-410827714.png

点击可以跳转带代码位置,显示对应耗时

1834753-20230106164721113-1798268247.png

1834753-20230106164811401-1423354625.png

这段代码在Performance中显示可以看到b函数的运行导致了耗时太高了,因为渲染和 JS 执行都在主线程,在一个 Event Loop 中,会相互阻塞,如果 JS 有长时间执行的 Task,就会阻塞渲染,导致页面卡顿。所以,性能分析主要的目的是找到 long task,之后消除它。

我们优化的目标是把两个 long task 中的耗时逻辑(循环累加)给去掉或者拆分成多个 task。

但明显我们这里的逻辑没啥好拆分的,它就是一个大循环。

那么能不能不放在主线程跑,放到其他线程跑呢?浏览器的 web worker 好像就是做耗时计算的性能优化的。
创建worker.js

// worker
const workercode = () => {
    const compute = (num) => {
        let total = 0;
        for (let i = 0; i < num; i++) {
            total += i;
        }
        return total
    }
    this.onmessage = function (e) {
        const reslut = compute(e.data)
        this.postMessage(reslut);
    }
};

let code = workercode.toString();
code = code.substring(code.indexOf("{") + 1, code.lastIndexOf("}"));

const blob = new Blob([code], { type: "application/javascript" });
const worker_script = URL.createObjectURL(blob);

module.exports = worker_script;

需要使用的页面引入

import worker_script from "./worker";
  useEffect(() => {
    const myWorker = new Worker(worker_script);
    myWorker.postMessage(10 * 10000 * 10000);
    myWorker.onmessage = (m) => {
      console.log("msg from worker: ", m.data);
    };
  });

image
可以看到计算被转移到worker,虽然还是long task,但是不阻塞主线程,计算量也在那里没办法优化

这样,我们通过把计算量拆分到 worker 线程,充分利用了多核 cpu 的能力,解决了主线程的 long task 问题,界面交互会很流畅。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK