激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務(wù)器之家 - 編程語(yǔ)言 - JavaScript - React - 從框架作者角度聊:React調(diào)度算法的迭代過(guò)程

從框架作者角度聊:React調(diào)度算法的迭代過(guò)程

2022-01-10 23:46魔術(shù)師卡頌卡頌 React

React內(nèi)部最難理解的地方就是「調(diào)度算法」,不僅抽象、復(fù)雜,還重構(gòu)了一次。可以說(shuō),只有React團(tuán)隊(duì)自己才能完全理解這套算法。既然這樣,那本文嘗試從React團(tuán)隊(duì)成員的視角出發(fā),來(lái)聊聊「調(diào)度算法」。

從框架作者角度聊:React調(diào)度算法的迭代過(guò)程

大家好,我卡頌。

React內(nèi)部最難理解的地方就是「調(diào)度算法」,不僅抽象、復(fù)雜,還重構(gòu)了一次。

可以說(shuō),只有React團(tuán)隊(duì)自己才能完全理解這套算法。

既然這樣,那本文嘗試從React團(tuán)隊(duì)成員的視角出發(fā),來(lái)聊聊「調(diào)度算法」。

什么是調(diào)度算法

React在v16之前面對(duì)的主要性能問(wèn)題是:當(dāng)組件樹(shù)很龐大時(shí),更新?tīng)顟B(tài)可能造成頁(yè)面卡頓,根本原因在于:更新流程是「同步、不可中斷的」。

為了解決這個(gè)問(wèn)題,React提出Fiber架構(gòu),意在「將更新流程變?yōu)楫惒健⒖芍袛嗟摹埂?/p>

最終實(shí)現(xiàn)的交互流程如下:

  1. 不同交互產(chǎn)生不同優(yōu)先級(jí)的更新(比如onClick回調(diào)中的更新優(yōu)先級(jí)最高,useEffect回調(diào)中觸發(fā)的更新優(yōu)先級(jí)一般)
  2. 「調(diào)度算法」從眾多更新中選出一個(gè)優(yōu)先級(jí)作為本次render的優(yōu)先級(jí)
  3. 以步驟2選擇的優(yōu)先級(jí)對(duì)組件樹(shù)進(jìn)行render

在render過(guò)程中,如果又觸發(fā)交互流程,步驟2又選出一個(gè)更高優(yōu)先級(jí),則之前的render中斷,以新的優(yōu)先級(jí)重新開(kāi)始render。

本文要聊的就是步驟2中的「調(diào)度算法」。

expirationTime調(diào)度算法

「調(diào)度算法」需要解決的最基本的問(wèn)題是:如何從眾多更新中選擇其中一個(gè)更新的優(yōu)先級(jí)作為本次render的優(yōu)先級(jí)?

最早的算法叫做expirationTime算法。

具體來(lái)說(shuō),更新的優(yōu)先級(jí)與「觸發(fā)交互的當(dāng)前時(shí)間」及「優(yōu)先級(jí)對(duì)應(yīng)的延遲時(shí)間」相關(guān):

  1. // MAX_SIGNED_31_BIT_INT為最大31 bit Interger 
  2. update.expirationTime = MAX_SIGNED_31_BIT_INT - (currentTime + updatePriority); 

例如,高優(yōu)先級(jí)更新u1、低優(yōu)先級(jí)更新u2的updatePriority分別為0、200,則

  1. MAX_SIGNED_31_BIT_INT - (currentTime + 0) > MAX_SIGNED_31_BIT_INT - (currentTime + 200) 
  2.  
  3. // 即 
  4. u1.expirationTime > u2.expirationTime; 

代表u1優(yōu)先級(jí)更高。

expirationTime算法的原理簡(jiǎn)單易懂:每次都選出所有更新中「優(yōu)先級(jí)最高的」。

如何表示“批次”

除此之外,還有個(gè)問(wèn)題需要解決:如何表示「批次」?

「批次」是什么?考慮如下例子:

  1. // 定義狀態(tài)num 
  2. const [num, updateNum] = useState(0); 
  3.  
  4. // ...某些修改num的地方 
  5. // 修改的方式1 
  6. updateNum(3); 
  7. // 修改的方式2 
  8. updateNum(num => num + 1); 

兩種「修改狀態(tài)的方式」都會(huì)創(chuàng)建更新,區(qū)別在于:

  • 第一種方式,不需考慮更新前的狀態(tài),直接將狀態(tài)num修改為3
  • 第二種方式,需要基于「更新前的狀態(tài)」計(jì)算新?tīng)顟B(tài)

由于第二種方式的存在,更新之間可能有連續(xù)性。

所以「調(diào)度算法」計(jì)算出一個(gè)優(yōu)先級(jí)后,組件render時(shí)實(shí)際參與計(jì)算「當(dāng)前狀態(tài)的值」的是:

「計(jì)算出的優(yōu)先級(jí)對(duì)應(yīng)更新」 + 「與該優(yōu)先級(jí)相關(guān)的其他優(yōu)先級(jí)對(duì)應(yīng)更新」

這些相互關(guān)聯(lián),有連續(xù)性的更新被稱為一個(gè)「批次」(batch)。

expirationTime算法計(jì)算「批次」的方式也簡(jiǎn)單粗暴:優(yōu)先級(jí)大于某個(gè)值(priorityOfBatch)的更新都會(huì)劃為同一批次。

  1. const isUpdateIncludedInBatch = priorityOfUpdate >= priorityOfBatch; 

expirationTime算法保證了render異步可中斷、且永遠(yuǎn)是最高優(yōu)先級(jí)的更新先被處理。

這一時(shí)期該特性被稱為Async Mode。

IO密集型場(chǎng)景

Async Mode可以解決以下問(wèn)題:

  1. 組件樹(shù)邏輯復(fù)雜導(dǎo)致更新時(shí)卡頓(因?yàn)榻M件render變?yōu)榭芍袛?
  2. 重要的交互更快響應(yīng)(因?yàn)椴煌换ギa(chǎn)生更新的優(yōu)先級(jí)不同)

這些問(wèn)題統(tǒng)稱為CPU密集型問(wèn)題。

在前端,還有一類問(wèn)題也會(huì)影響體驗(yàn),那就是「請(qǐng)求數(shù)據(jù)造成的等待」。這類問(wèn)題被稱為IO密集型問(wèn)題。

為了解決IO密集型問(wèn)題的,React提出了Suspense。考慮如下代碼:

  1. const App = () => { 
  2.   const [count, setCount] = useState(0); 
  3.    
  4.   useEffect(() => { 
  5.     const t = setInterval(() => { 
  6.       setCount(count => count + 1); 
  7.     }, 1000); 
  8.     return () => clearInterval(t); 
  9.   }, []); 
  10.    
  11.   return ( 
  12.     <> 
  13.       <Suspense fallback={<div>loading...</div>}> 
  14.         <Sub count={count} /> 
  15.       </Suspense> 
  16.       <div>count is {count}</div> 
  17.     </> 
  18.   ); 
  19. }; 

其中:

  • 每過(guò)一秒會(huì)觸發(fā)一次更新,將狀態(tài)count更新為count => count + 1
  • 在Sub中會(huì)發(fā)起異步請(qǐng)求,請(qǐng)求返回前,包裹Sub的Suspense會(huì)渲染fallback

假設(shè)請(qǐng)求三秒后返回,理想情況下,請(qǐng)求發(fā)起前后UI會(huì)依次顯示為:

  1. // Sub內(nèi)請(qǐng)求發(fā)起前 
  2. <div class=“sub”>I am sub, count is 0</div> 
  3. <div>count is 0</div> 
  4.  
  5. // Sub內(nèi)請(qǐng)求發(fā)起第1秒 
  6. <div>loading...</div> 
  7. <div>count is 1</div> 
  8.  
  9. // Sub內(nèi)請(qǐng)求發(fā)起第2秒 
  10. <div>loading...</div> 
  11. <div>count is 2</div> 
  12.  
  13. // Sub內(nèi)請(qǐng)求發(fā)起第3秒 
  14. <div>loading...</div> 
  15. <div>count is 3</div> 
  16.  
  17. // Sub內(nèi)請(qǐng)求成功后 
  18. <div class=“sub”>I am sub, request success, count is 4</div> 
  19. <div>count is 4</div> 

從用戶的視角觀察,有兩個(gè)任務(wù)在并發(fā)執(zhí)行:

  1. 請(qǐng)求Sub的任務(wù)(觀察第一個(gè)div的變化)
  2. 改變count的任務(wù)(觀察第二個(gè)div的變化)

Suspense帶來(lái)了「多任務(wù)并發(fā)執(zhí)行」的直觀感受。

因此,Async Mode(異步模式)也更名為Concurrent Mode(并發(fā)模式)。

一個(gè)無(wú)法解決的bug

那么Suspense對(duì)應(yīng)更新的優(yōu)先級(jí)是高還是低呢?

當(dāng)請(qǐng)求成功后,合理的邏輯應(yīng)該是「盡快展示成功后的UI」。所以Suspense對(duì)應(yīng)更新應(yīng)該是高優(yōu)先級(jí)更新。那么,在示例中共有兩類更新:

Suspense對(duì)應(yīng)的高優(yōu)IO更新,簡(jiǎn)稱u0

每秒產(chǎn)生的低優(yōu)CPU更新,簡(jiǎn)稱u1、u2、u3等

在expirationTime算法下:

  1. // u0優(yōu)先級(jí)遠(yuǎn)大于u1、u2、u3... 
  2. u0.expirationTime >> u1.expirationTime > u2.expirationTime > … 

u0優(yōu)先級(jí)最高,則u1及之后的更新都需要等待u0執(zhí)行完畢后再進(jìn)行。

而u0需要等待「請(qǐng)求完畢」才能執(zhí)行。所以,請(qǐng)求發(fā)起前后UI會(huì)依次顯示為:

  1. // Sub內(nèi)請(qǐng)求發(fā)起前 
  2. <div class=“sub”>I am sub, count is 0</div> 
  3. <div>count is 0</div> 
  4.  
  5. // Sub內(nèi)請(qǐng)求發(fā)起第1秒 
  6. <div>loading...</div> 
  7. <div>count is 0</div> 
  8.  
  9. // Sub內(nèi)請(qǐng)求發(fā)起第2秒 
  10. <div>loading...</div> 
  11. <div>count is 0</div> 
  12.  
  13. // Sub內(nèi)請(qǐng)求發(fā)起第3秒 
  14. <div>loading...</div> 
  15. <div>count is 0</div> 
  16.  
  17. // Sub內(nèi)請(qǐng)求成功后 
  18. <div class=“sub”>I am sub, request success, count is 4</div> 
  19. <div>count is 4</div> 

從用戶的視角觀察,第二個(gè)div被卡住了3秒后突然變?yōu)?。

所以,只考慮CPU密集型場(chǎng)景的情況下,「高優(yōu)更新先執(zhí)行」的算法并無(wú)問(wèn)題。

但考慮IO密集型場(chǎng)景的情況下,高優(yōu)IO更新會(huì)阻塞低優(yōu)CPU更新,這顯然是不對(duì)的。

所以expirationTime算法并不能很好支持并發(fā)更新。

expirationTime算法在線Demo[1]

出現(xiàn)bug的原因

expirationTime算法最大的問(wèn)題在于:expirationTime字段耦合了「優(yōu)先級(jí)」與「批次」這兩個(gè)概念,限制了模型的表達(dá)能力。

這導(dǎo)致高優(yōu)IO更新不會(huì)與低優(yōu)CPU更新劃為同一「批次」。那么低優(yōu)CPU更新就必須等待高優(yōu)IO更新處理完后再處理。

如果不同更新能根據(jù)實(shí)際情況靈活劃分「批次」,就不會(huì)產(chǎn)生這個(gè)bug。

重構(gòu)迫在眉睫,并且重構(gòu)的目標(biāo)很明確:將「優(yōu)先級(jí)」與「批次」拆分到兩個(gè)字段中。

Lane調(diào)度算法

新的調(diào)度算法被稱為L(zhǎng)ane,他是如何定義「優(yōu)先級(jí)」與「批次」呢?

對(duì)于優(yōu)先級(jí),一個(gè)lane就是一個(gè)32bit Interger,最高位為符號(hào)位,所以最多可以有31個(gè)位參與運(yùn)算。

不同優(yōu)先級(jí)對(duì)應(yīng)不同lane,越低的位代表越高的優(yōu)先級(jí),比如:

  1. // 對(duì)應(yīng)SyncLane,為最高優(yōu)先級(jí) 
  2. 0b0000000000000000000000000000001 
  3. // 對(duì)應(yīng)InputContinuousLane 
  4. 0b0000000000000000000000000000100 
  5. // 對(duì)應(yīng)DefaultLane 
  6. 0b0000000000000000000000000010000 
  7. // 對(duì)應(yīng)IdleLane 
  8. 0b0100000000000000000000000000000 
  9. // 對(duì)應(yīng)OffscreenLane,為最低優(yōu)先級(jí) 
  10. 0b1000000000000000000000000000000 

「批次」則由lanes定義,一個(gè)lanes同樣也是一個(gè)32bit Interger,代表「一到多個(gè)lane的集合」。

可以用位運(yùn)算很輕松的將多個(gè)lane劃入同一個(gè)批次:

  1. // 要使用的批次 
  2. let lanesForBatch = 0; 
  3.  
  4. const laneA = 0b0000000000000000000000001000000; 
  5. const laneB = 0b0000000000000000000000000000001; 
  6.  
  7. // 將laneA納入批次中 
  8. lanesForBatch |= laneA; 
  9. // 將laneB納入批次中 
  10. lanesForBatch |= laneB; 

上文提到的Suspense的bug是由于expirationTime算法不能靈活劃定批次導(dǎo)致的。

lanes就完全沒(méi)有這種顧慮,任何想劃定為同一「批次」的優(yōu)先級(jí)(lane)都能用位運(yùn)算輕松搞定。

Lane算法在線Demo[2]

總結(jié)

「調(diào)度算法」要解決兩個(gè)問(wèn)題:

  1. 選取優(yōu)先級(jí)
  2. 選取批次

expirationTime算法中使用的expirationTime字段耦合了這兩個(gè)概念,導(dǎo)致不夠靈活。

Lane算法的出現(xiàn)解決了以上問(wèn)題。

參考資料

[1]expirationTime算法在線Demo:

https://codesandbox.io/s/usetransition-stop-reacting-passed-props-updates-forked-5e7lh

[2]Lane算法在線Demo:

 

https://codesandbox.io/s/usetransition-stop-reacting-passed-props-updates-zoqm2?file=/src/index.js

原文鏈接:https://mp.weixin.qq.com/s/tkEYtRTrZovA4uVrfnNUDQ

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲视频网 | 线观看免费完整aaa 一二区成人影院电影网 | 久久91亚洲人成电影网站 | 狠狠操人人干 | 俄罗斯16一20sex牲色另类 | 99欧美精品 | 久久视频精品 | 精品久久久久久久久久久久久久久久久久久 | 蜜桃传媒视频麻豆第一区免费观看 | 一级做a爱视频 | 免费观看高清视频网站 | 欧美成人高清视频 | 97伦理 | 欧美激情视频一区二区免费 | 日日摸夜夜添夜夜添牛牛 | 亚洲精品一区二区三区免 | 欧洲狠狠鲁 | 黄色网www| 成人毛片100部 | 大学生一级毛片在线视频 | 亚洲aⅴ免费在线观看 | 成人午夜在线免费视频 | 成人做爰高潮片免费视频韩国 | 成人毛片100免费观看 | 毛片大全在线观看 | 男女羞羞的视频 | 色视频在线观看 | 国产精品一区在线免费观看 | 在线观看91精品 | 久久99亚洲精品久久99果 | 日韩精品中文字幕一区 | 久久精品日产第一区二区三区 | 国产成人精品一区二区仙踪林 | 成人羞羞在线观看网站 | 久久久久久久久久久久久久久久久久 | 天天看天天摸天天操 | 国产免费一级大片 | 在线成人免费观看www | 成人午夜激情视频 | 被啪羞羞视频在线观看 | 羞羞的动漫在线观看 |