歡迎閱讀本系列其他文章 【前端調試】- 更好的調試方式 VSCode Debugger 【前端調試】- 斷點調試的正確打開方式 介紹 首先簡單過一下Performance的使用,打開網頁點擊控制台Performance,錄製5s的數據 其中 Main 這部分就是網頁的主線程,也就是執行 Event ...
歡迎閱讀本系列其他文章
【前端調試】- 更好的調試方式 VSCode Debugger
【前端調試】- 斷點調試的正確打開方式
介紹
首先簡單過一下Performance的使用,打開網頁點擊控制台Performance,錄製5s的數據
其中 Main 這部分就是網頁的主線程,也就是執行 Event Loop 的部分:
灰色就代表巨集任務 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();
});
點擊可以跳轉帶代碼位置,顯示對應耗時
這段代碼在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);
};
});
可以看到計算被轉移到worker,雖然還是long task,但是不阻塞主線程,計算量也在那裡沒辦法優化
這樣,我們通過把計算量拆分到 worker 線程,充分利用了多核 cpu 的能力,解決了主線程的 long task 問題,界面交互會很流暢。