1、ExpirationTime的做用
在React
中,爲防止某個update
由於優先級的緣由一直被打斷而未能執行。React
會設置一個ExpirationTime
,當時間到了ExpirationTime
的時候,若是某個update
還未執行的話,React
將會強制執行該update
,這就是ExpirationTime
的做用。react
2、位置
在React源碼解析之ReactDOM.render()中,已經講解了updateContainer()
:git
export function updateContainer( element: ReactNodeList, container: OpaqueRoot, parentComponent: ?React$Component<any, any>, callback: ?Function, ): ExpirationTime { ... //計算過時時間,這是React優先級更新很是重要的點 const expirationTime = computeExpirationForFiber( currentTime, current, suspenseConfig, ); ... }
computeExpirationForFiber
:github
//爲fiber對象計算expirationTime export function computeExpirationForFiber( currentTime: ExpirationTime, fiber: Fiber, suspenseConfig: null | SuspenseConfig, ): ExpirationTime { ... // Compute an expiration time based on the Scheduler priority. switch (priorityLevel) { case ImmediatePriority: expirationTime = Sync; break; case UserBlockingPriority: // TODO: Rename this to computeUserBlockingExpiration //一個是計算交互事件(如點擊)的過時時間 expirationTime = computeInteractiveExpiration(currentTime); break; case NormalPriority: case LowPriority: // TODO: Handle LowPriority // TODO: Rename this to... something better. //一個是計算異步更新的過時時間 expirationTime = computeAsyncExpiration(currentTime); break; case IdlePriority: expirationTime = Never; break; default: invariant(false, 'Expected a valid priority level'); } ... }
咱們能夠看到有兩個計算expirationTime
的方法,分別爲computeInteractiveExpiration()
和computeAsyncExpiration()
異步
先看下computeAsyncExpiration()
性能
3、computeAsyncExpiration()
做用:
返回低優先級(普通異步更新)的expirationTime
(過時時間)this
源碼:spa
//低權限的過時時間 export const LOW_PRIORITY_EXPIRATION = 5000; export const LOW_PRIORITY_BATCH_SIZE = 250; //普通的異步的expirationTime export function computeAsyncExpiration( currentTime: ExpirationTime, ): ExpirationTime { return computeExpirationBucket( currentTime, //5000 LOW_PRIORITY_EXPIRATION, //250 LOW_PRIORITY_BATCH_SIZE, ); }
解析:currentTime
先按下不表,LOW_PRIORITY_EXPIRATION
即5000
,LOW_PRIORITY_BATCH_SIZE
即250
,注意它的名字LOW_PRIORITY_BATCH_SIZE
,下面會提到code
4、computeExpirationBucket()
做用:
計算過時時間orm
源碼:對象
//1073741823 export const Sync = MAX_SIGNED_31_BIT_INT; //1073741822 export const Batched = Sync - 1; const UNIT_SIZE = 10; //1073741821 const MAGIC_NUMBER_OFFSET = Batched - 1; function ceiling(num: number, precision: number): number { return (((num / precision) | 0) + 1) * precision; } //計算過時時間 function computeExpirationBucket( currentTime, expirationInMs, bucketSizeMs, ): ExpirationTime { return ( //1073741821 MAGIC_NUMBER_OFFSET - ceiling( // 1073741821-currentTime+(high 150 或者 low 5000 /10) , MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, //(high 100 或者 low 250 /10 ) bucketSizeMs / UNIT_SIZE, ) ); }
解析:
(1)MAX_SIGNED_31_BIT_INT
// Max 31 bit integer. The max integer size in V8 for 32-bit systems. // Math.pow(2, 30) - 1 // 0b111111111111111111111111111111 //整型最大數值,是V8中針對32位系統所設置的最大值 export default 1073741823;
(2)| 0
的意思是取整
console.log(16/3 |0) //5
(3)根據computeExpirationBucket()
裏面的公式,計算下異步更新的過時時間:
//low 狀況 1073741821-ceiling(1073741821-currentTime+500,25) 1073741821-((((1073741821-currentTime+500) / 25) | 0) + 1) * 25 1073741821-((1073741821/25-currentTime/25+20 | 0) + 1) * 25 1073741821-((1073741821/25-currentTime/25+20*25/25 | 0) + 1) * 25 1073741821-((1073741821-currentTime+500)/25 | 0)*25 - 25 1073741796-((1073741821-currentTime+500)/25 | 0)*25 1073741796-((1073742321-currentTime)/25 | 0)*25 //======咱們直接取最後四位來探索規律=================== 1796-((2321-currentTime)/25 | 0)*25 //假設 currentTime 是 2000 1796-(2321- 2000 /25 | 0)*25 //1796-300 //currentTime是2010 1796-(311/25 | 0)*25 //1796-300 //currentTime是2024 1796-(311/25 | 0)*25 //1796-275 //currentTime是2025 1796-(311/25 | 0)*25 //1796-275
能夠看到,低優先的過時時間間隔是25ms
同理,高優先級的過時時間間隔是10ms
//high 狀況 1073741821-ceiling(1073741821-currentTime+15,10)
**也就是說,React
低優先級update
的expirationTime
間隔是25ms
,React
讓兩個相近(25ms
內)的update
獲得相同的expirationTime
,目的就是讓這兩個update
自動合併成一個Update
,從而達到批量更新的目的,就像LOW_PRIORITY_BATCH_SIZE
的名字同樣,自動合併批量更新。**
想象一下,開發者不停地使用setState()
更新ReactApp
,若是不把相近的update
合併的話,會嚴重影響性能,就像提到的doubleBuffer
同樣,React
爲提升性能,考慮得很是全面!
(完)