成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

聊聊React內部的性能優化沒有達到極致?

開發 前端
本文通過了解eagerState的邏輯,回答一個問題:React的性能優化達到極致了么?

大家好,我卡頌。

對于如下這個常見交互步驟:

  1. 點擊按鈕,觸發狀態更新。
  2. 組件render。
  3. 視圖渲染。

你覺得哪些步驟有「性能優化的空間」呢?

答案是:1和2。

對于「步驟1」,如果狀態更新前后沒有變化,則可以略過剩下的步驟。這個優化策略被稱為eagerState。

對于「步驟2」,如果組件的子孫節點沒有狀態變化,可以跳過子孫組件的render。這個優化策略被稱為bailout。

看起來eagerState的邏輯很簡單,只需要比較「狀態更新前后是否有變化」。

然而,實踐上卻很復雜。

本文通過了解eagerState的邏輯,回答一個問題:React的性能優化達到極致了么?

一個奇怪的例子

考慮如下組件:

function App() {
const [num, updateNum] = useState(0);
console.log("App render", num);
return (
<div onClick={() => updateNum(1)}>
<Child />
</div>
);
}
function Child() {
console.log("child render");
return <span>child</span>;
}

在線Demo地址[1]。

首次渲染,打印:

App render 0
child render

第一次點擊div,打印:

App render 1
child render

第二次點擊div,打印:

App render 1

第三、四......次點擊div,不打印。

在「第二次」點擊中,打印了App render 1,沒有打印child render。代表App的子孫組件沒有render,命中了bailout。

「第三次及之后」的點擊,什么都不打印,代表沒有組件render,命中了eagerState。

那么問題來了,明明第一、二次點擊都是執行updateNum(1),顯然狀態是沒有變化的,為什么第二次沒有命中eagerState?

eagerState的觸發條件

首先我們需要明白,為什么叫eagerState(急迫的狀態)?

通常,什么時候能獲取到最新狀態呢?組件render的時候。

當組件render,useState執行并返回最新狀態。

考慮如下代碼:

const [num, updateNum] = useState(0);

useState執行后返回的num就是最新狀態。

之所以useState執行時才能計算出最新狀態,是因為狀態是根據「一到多個更新」計算而來的。

比如,在如下點擊事件中觸發3個更新:

const onClick = () => {
updateNum(100);
updateNum(num => num + 1);
updateNum(num => num * 2);
}

組件render時num的最新狀態應該是多少呢?

  • 首先num變為100。
  • 100 + 1 = 101。
  • 101 * 2 = 202。

所以,useState會返回202作為num的最新狀態。

實際情況會更復雜,更新擁有自己的優先級,所以在render前不能確定「究竟是哪些更新會參與狀態的計算」。

所以,在這種情況下組件必須render,useState必須執行才能知道num的最新狀態是多少。

那就沒法提前將num的最新狀態與num的當前狀態比較,判斷「狀態是否變化」。

而eagerState的意義在于,在「某種情況」下,我們可以在組件render前就提前計算出最新狀態(這就是eagerState的由來)。

這種情況下組件不需要render就能比較「狀態是否變化」。

那么是什么情況呢?

答案是:當前組件上「不存在更新」的時候。

當不存在更新時,本次更新就是組件的第一個更新。在只有一個更新的情況下是能確定最新狀態的。

所以,eagerState的前提是:

當前組件不存在更新,那么首次觸發狀態更新時,就能立刻計算出最新狀態,進而與當前狀態比較。

如果兩者一致,則省去了后續render的過程。

這就是eagerState的邏輯。但遺憾的是,實際情況還要再復雜一丟丟。

先讓我們看一個「看似不相干」的例子。

必要的React源碼知識

對于如下組件:

function App() {
const [num, updateNum] = useState(0);
window.updateNum = updateNum;
return <div>{num}</div>;
}

在控制臺執行如下代碼,可以改變視圖顯示的num么?

window.updateNum(100)

答案是:可以。

因為App組件對應fiber(保存組件相關信息的節點)已經被作為「預設的參數」傳遞給window.updateNum了:

// updateNum的實現類似這樣
// 其中fiber就是App對應fiber
const updateNum = dispatchSetState.bind(null, fiber, queue);

所以updateNum執行時是能獲取App對應fiber的。

然而,一個組件實際有2個fiber,他們:

  • 一個保存「當前視圖」對應的相關信息,被稱為current fiber。
  • 一個保存「接下來要變化的視圖」對應的相關信息,被稱為wip fiber。

updateNum中被預設的是wip fiber。

當組件觸發更新后,會在組件對應的2個fiber上都「標記更新」。

當組件render時,useState會執行,計算出新的狀態,并把wip fiber上的「更新標記」清除。

當視圖完成渲染后,current fiber與wip fiber會交換位置(也就是說本次更新的wip fiber會變為下次更新的current fiber)。

回到例子

剛才談到,eagerState的前提是:「當前組件不存在更新」。

具體來講,是組件對應的current fiber與wip fiber都不存在更新。

回到我們的例子:

第一次點擊div,打印:

App render 1
child render

current fiber與wip fiber同時標記更新。

render后wip fiber的「更新標記」清除。

此時current fiber還存在「更新標記」。

完成渲染后,current fiber與wip fiber會交換位置。

變成:wip fiber存在更新,current fiber不存在更新。

所以第二次點擊div時,由于wip fiber存在更新,沒有命中eagerState,于是打印:

App render 1

render后wip fiber的「更新標記」清除。

此時兩個fiber上都不存在「更新標記」。所以后續點擊div都會觸發eagerState,組件不會render。

總結

由于React內部各個部分間互相影響,導致React性能優化的結果有時讓開發者迷惑。

為什么沒有聽到多少人抱怨呢?因為性能優化只會反映在指標上,不會影響交互邏輯。

通過本文我們發現,React性能優化并沒有做到極致,由于存在兩個fiber,eagerState策略并沒有達到最理想的狀態。

參考資料

[1]在線Demo地址:

https://codesandbox.io/s/frosty-cerf-mg64o5?file=/src/App.js:188-200。

責任編輯:姜華 來源: 魔術師卡頌
相關推薦

2019-07-25 13:22:43

AndroidAPK文件優化

2024-02-29 18:06:39

HTTP性能優化

2009-07-24 11:43:26

PAL虛擬化性能組件

2020-12-31 05:33:34

軟件性能優化

2021-08-27 14:26:06

開發技能React

2019-02-25 07:07:38

技巧React 優化

2023-12-15 17:09:28

.NET8Primitives性能

2019-07-23 09:20:15

Kafka批量處理客戶端

2024-02-04 10:20:19

蘋果內存

2023-11-01 17:57:56

React應用程序性能

2022-08-03 09:11:31

React性能優化

2016-12-19 10:00:00

React性能優化

2021-11-18 08:20:22

接口索引SQL

2020-01-15 11:30:59

編碼優化性能

2022-02-21 13:27:11

接口性能優化索引命令

2021-01-14 08:58:12

Synchronize鎖操作

2020-06-22 07:30:00

React開發工具

2021-11-05 10:36:19

性能優化實踐

2021-02-05 15:35:21

Redis數據庫命令

2021-09-18 10:07:23

開發技能代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成年人在线观看 | 尤物视频在线免费观看 | 亚洲免费一区二区 | 午夜精品久久久久久久久久久久久 | 精品乱子伦一区二区三区 | 日韩一二三区视频 | 欧美在线一级 | 欧美日韩三区 | 亚洲免费网| 免费黄色大片 | 成人免费影院 | 国产成人精品午夜 | 亚洲高清一区二区三区 | 美女天堂 | 亚洲综合五月天婷婷 | 天堂精品视频 | 久久久久久久一区 | 国产成人免费视频网站高清观看视频 | 色婷婷综合久久久中文字幕 | 狠狠色综合久久丁香婷婷 | 国产精品国产亚洲精品看不卡15 | 国产精品久久久久久久久久免费看 | 欧美寡妇偷汉性猛交 | 久视频在线 | 久草中文在线 | 看一级毛片| 日韩成人在线免费视频 | 成年人黄色一级毛片 | 男女网站免费 | 精品动漫一区 | 人人玩人人添人人澡欧美 | 中文字幕动漫成人 | 激情av网站 | 综合色站导航 | 欧美国产激情 | 精品一区二区三区四区五区 | 国产一区二区在线播放 | 91色在线| 久久之精品| 毛片一区 | 欧美久久国产精品 |