自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

給女朋友講React18新特性:startTransition

開(kāi)發(fā) 前端
startTransition的出現(xiàn)當(dāng)然不是為了逆轉(zhuǎn)命運(yùn),而是為了逆轉(zhuǎn)React的更新流程。在聊startTransition的具體應(yīng)用場(chǎng)景前,我先來(lái)聊聊React是如何揚(yáng)長(zhǎng)避短的。

[[406706]]

大家好,我是卡頌。

我女友是個(gè)鐵憨憨,又菜又愛(ài)玩。

她問(wèn)我:“卡卡,你說(shuō)時(shí)光真的可以重來(lái)?命運(yùn)真是可以選擇的么?”

我:“可以的,React18的新特性startTransition就行。”

startTransition的出現(xiàn)當(dāng)然不是為了逆轉(zhuǎn)命運(yùn),而是為了逆轉(zhuǎn)React的更新流程。

"在聊startTransition的具體應(yīng)用場(chǎng)景前,我先來(lái)聊聊React是如何揚(yáng)長(zhǎng)避短的。"

編譯時(shí)的短,運(yùn)行時(shí)的長(zhǎng)

如果我們用「重編譯時(shí)還是運(yùn)行時(shí)」區(qū)分前端框架。那么Vue和Svelte就是「重編譯時(shí)」的杰出代表。

在「編譯時(shí)」,這兩個(gè)框架可以分離模版語(yǔ)法中「變」與「不變」的部分,減少運(yùn)行時(shí)的代碼邏輯。

而React由于使用JSX(而非模版語(yǔ)法)描述視圖,走的是「重運(yùn)行時(shí)」的路線。

  • 不是React不想在「編譯時(shí)」做優(yōu)化,奈何JSX實(shí)在太靈活,做不到啊......

所以他的優(yōu)化策略也都是偏「運(yùn)行時(shí)」。

在「運(yùn)行時(shí)」,最大的開(kāi)銷(xiāo)是:狀態(tài)更新到視圖變化中間的計(jì)算步驟。

這個(gè)步驟是通過(guò)「遍歷Fiber樹(shù)」實(shí)現(xiàn)的。

常規(guī)的「運(yùn)行時(shí)優(yōu)化策略」,比如:

  • React.memo
  • PureComponent
  • shouldComponentUpdate

優(yōu)化方向都是:減少遍歷時(shí)需要遍歷的Fiber節(jié)點(diǎn)數(shù)量。

雖說(shuō)性能優(yōu)化的收益可以積少成多,但是React團(tuán)隊(duì)早已不滿(mǎn)足這種局部的小優(yōu)化。

性能優(yōu)化新思

路他們的思路是:

不同更新觸發(fā)的視圖變化顯然是有輕重緩急的。

如果能區(qū)分更新的優(yōu)先級(jí),讓高優(yōu)更新對(duì)應(yīng)的視圖變化先渲染,那么就能在設(shè)備性能不變的情況下,讓用戶(hù)更快看到他們想看到的UI。

比如:對(duì)于這樣一個(gè)搜索下拉框:

用戶(hù)期望:輸入框輸入的內(nèi)容要實(shí)時(shí)反映在視圖上(表現(xiàn)為輸入內(nèi)容不能卡頓)。

而結(jié)果下拉框的展示是可以有延遲的。

基于以上邏輯,React希望提供一個(gè)API,讓用戶(hù)告訴自己,哪些更新是「高優(yōu)」的,哪些是「低優(yōu)」的。

這樣,React就能知道優(yōu)先渲染誰(shuí)了。

這個(gè)API,就是startTransition。

startTransition的使用

接下來(lái),我們用一個(gè)Demo[1]演示startTransition的使用。

這個(gè)Demo會(huì)渲染一棵「畢達(dá)哥拉斯樹(shù)」。

拖動(dòng)左邊滑塊會(huì)改變樹(shù)渲染的節(jié)點(diǎn)數(shù)量。

拖動(dòng)頂部滑塊會(huì)改變樹(shù)的傾斜角度。

最頂上有個(gè)幀雷達(dá),可以實(shí)時(shí)顯示更新過(guò)程中的掉幀情況。

當(dāng)不點(diǎn)擊Use startTransition按鈕,拖動(dòng)頂上的滑塊。

圖片

可以看到:拖動(dòng)并不流暢,頂上的幀雷達(dá)顯示掉幀(出現(xiàn)黃色、紅色扇面)

當(dāng)點(diǎn)擊Use startTransition按鈕,拖動(dòng)頂上的滑塊。

圖片

可以明顯看到:拖動(dòng)變流暢,頂上的幀雷達(dá)顯示掉幀的情況變少

讓我們節(jié)選Demo的代碼看看,究竟發(fā)生了什么。

Demo都做了什么?

首先,控制滑塊、樹(shù)傾斜角度、要渲染的節(jié)點(diǎn)數(shù)量是分離在不同state中的:

  1. // 左側(cè)滑塊的state 
  2. const [treeSizeInput, setTreeSizeInput] = useState(8); 
  3. // 控制渲染節(jié)點(diǎn)數(shù)量的state 
  4. const [treeSize, setTreeSize] = useState(8); 
  5.  
  6. // 頂部滑塊的state 
  7. const [treeLeanInput, setTreeLeanInput] = useState(0); 
  8. // 控制樹(shù)傾斜角度的state 
  9. const [treeLean, setTreeLean] = useState(0); 
  10.  
  11. // startTransition的hook版本 
  12. const [isLeaning, startTransition] = useTransition(); 

當(dāng)拖動(dòng)頂上的滑塊(改變樹(shù)的傾斜角度)會(huì)調(diào)用changeTreeLean方法:

  1. function changeTreeLean(event) { 
  2.     const value = Number(event.target.value); 
  3.     setTreeLeanInput(value); // update input 
  4.  
  5.     // update visuals 
  6.     if (enableStartTransition) { 
  7.         startTransition(() => { 
  8.             setTreeLean(value); 
  9.         }); 
  10.     } else { 
  11.         setTreeLean(value); 
  12.     } 

該方法會(huì)改變兩個(gè)state:

  • 通過(guò)調(diào)用setTreeLeanInput改變頂部滑塊位置相關(guān)的state —— treeLeanInput
  • 通過(guò)調(diào)用setTreeLean改變樹(shù)的傾斜角度相關(guān)的state —— treeLean

是否點(diǎn)擊Use startTransition按鈕的區(qū)別,就在于setTreeLean是否會(huì)被作為startTransition的回調(diào)執(zhí)行:

  1. // 是否開(kāi)啟startTransition 
  2. if (enableStartTransition) { 
  3.   startTransition(() => { 
  4.     setTreeLean(value); 
  5.   }); 
  6. else { 
  7.   setTreeLean(value); 

當(dāng)作為startTransition的回調(diào)執(zhí)行時(shí),setTreeLean改變的狀態(tài)(treeLean)對(duì)應(yīng)的視圖變化(即:改變樹(shù)的傾斜角度)會(huì)被視為「低優(yōu)先級(jí)的更新」。

即使其與改變滑塊狀態(tài)的方法(setTreeLeanInput)在同一上下文中執(zhí)行,

由于其優(yōu)先級(jí)較低,React會(huì)優(yōu)先處理「改變滑塊狀態(tài)」對(duì)應(yīng)的視圖變化。

表現(xiàn)為:滑塊的滑動(dòng)不卡頓。

startTransition的原理

鐵憨憨:“這么酷炫的功能實(shí)現(xiàn)起來(lái)一定很復(fù)雜吧?”

“恰恰相反,依賴(lài)于React底層實(shí)現(xiàn)的優(yōu)先級(jí)調(diào)度模型,startTransition的實(shí)現(xiàn)其實(shí)很簡(jiǎn)單!”

以剛才的代碼為例,如果加上console.log打?。?/p>

  1. console.log(1); 
  2. startTransition(() => { 
  3.   console.log(2); 
  4.   setTreeLean(value); 
  5. }); 
  6. console.log(3); 

那么會(huì)依次輸出:123

startTransition做的事情很簡(jiǎn)單,類(lèi)似這樣:

  1. let isInTransition = false 
  2.  
  3. function startTransition(fn) { 
  4.   isInTransition = true 
  5.   fn() 
  6.   isInTransition = false 

也就是說(shuō),當(dāng)調(diào)用startTransition,在其上下文中獲取到的全局變量isInTransition為true。

如果startTransition的回調(diào)函數(shù)fn中包含更新?tīng)顟B(tài)的方法(比如上文Demo中的setTreeLean),

那么這次更新就會(huì)被標(biāo)記為isTransition,類(lèi)似這樣:

  1. // 調(diào)用setTreeLean后會(huì)執(zhí)行的方法(偽代碼) 
  2. function setState(value) { 
  3.   stateQueue.push({ 
  4.     nextState: value, 
  5.     isTransition: isInTransition 
  6.   }) 

代表這是一個(gè)低優(yōu)先級(jí)的過(guò)渡更新。

接下來(lái),就是React內(nèi)部的調(diào)度、批處理與更新流程了。

  • 批處理的邏輯見(jiàn)給女朋友講React18新特性:Automatic batching

總結(jié)

今天,我們講了:

  • React為了彌補(bǔ)自身弱編譯時(shí)的缺點(diǎn),在運(yùn)行時(shí)作出的努力
  • startTransition本質(zhì)是讓開(kāi)發(fā)者手動(dòng)標(biāo)記更新的優(yōu)先級(jí)
  • startTransition的實(shí)現(xiàn)原理

鐵憨憨:”原來(lái)React為了性能優(yōu)化做了這么多努力,好復(fù)雜啊,我還是用Vue吧!“

我:“可不是嘛,React已經(jīng)在朝著實(shí)現(xiàn)一個(gè)瀏覽器的方向發(fā)展了。”

參考資料

[1]Demo:

https://swizec.com/blog/a-better-react-18-starttransition-demo/

 

責(zé)任編輯:姜華 來(lái)源: 魔術(shù)師卡頌
相關(guān)推薦

2021-06-22 07:30:07

React18Automatic b自動(dòng)批處理

2021-11-01 19:49:55

React組件模式

2024-04-24 11:00:05

React 18Fiber

2021-06-16 06:05:25

React18React

2021-06-15 14:54:23

ReactReact 18SSR

2020-10-25 08:22:28

V8 引擎JavaScript回調(diào)函數(shù)

2021-11-29 06:05:31

React組件前端

2019-03-12 09:43:14

反向代理正向代理服務(wù)器

2021-10-21 08:31:31

Spring循環(huán)依賴(lài)面試

2021-03-05 17:06:53

全排列組合子集

2019-04-09 09:40:23

2020-03-16 14:08:59

線程熔斷限流

2022-03-16 17:01:35

React18并發(fā)的React組件render

2022-03-30 14:22:55

ReactReact18并發(fā)特性

2023-03-21 08:31:13

ReconcilerFiber架構(gòu)

2021-09-14 12:00:11

VR字節(jié)跳動(dòng)

2019-10-09 10:45:16

云計(jì)算Web互聯(lián)網(wǎng)

2022-04-27 07:37:42

ReactReact18

2020-10-19 13:01:31

刪庫(kù)程序員思科

2021-03-11 16:45:29

TCP程序C語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)