做高效能的父母網(wǎng)站金華seo扣費
時間分片
- react的任務(wù)可以被打斷,其實就是基于時間分片的
- 人眼最高能識別的幀數(shù)不超過30幀,電影的幀數(shù)差不多是在24
- 瀏覽器的幀率一般來說是60幀,也就是每秒60個畫面, 平均一個畫面大概是16.5毫秒左右
- 瀏覽器正常的工作流程是運算渲染,運算,渲染運算渲染
- 在瀏覽器里面一個運算,加上一個渲染就是一幀
- 總的來講,可以理解為下面這張圖

- 比如 frame 是一幀,一個 Frame 就是16毫秒左右
- 黑色部分是瀏覽器的渲染,藍色部分是js的運算
- 在16毫秒以內(nèi)(一幀), 瀏覽器會重新渲染畫面,然后再加上JS的一輪事件循環(huán)的執(zhí)行
- 根據(jù)任務(wù)隊列循環(huán)下去,一秒 60 幀,每一幀都是 js的執(zhí)行 + 瀏覽器的渲染
- 但是, js它是單線程的, 會阻塞瀏覽器渲染, 假如 js執(zhí)行時間超長,占了 3 ~ 4幀
- js執(zhí)行的時候,瀏覽器是不能渲染的,那這個時候會有頁面卡頓的感覺
- 實際上這個時候是 js 在執(zhí)行
- 這個也是react它去遞歸渲染的時候的問題
- 遞歸渲染,它就是屬于長進程,相當于在 render 的時候 js 一直把渲染進程給卡住
- 這個是很苦惱的問題,所以誕生了fiber架構(gòu), react希望能夠把任務(wù)分片處理
- 這個時候就提到了一個概念,就是 fiber reconciler 要做的事情
- 它如何讓我們把時間分片,然后讓又讓瀏覽器不卡頓的呢?
- 其實特別的巧妙,谷歌瀏覽器底層提供的一個東西叫做 requestIdleCallback
- 前面說到一幀(16ms左右) 是 渲染 + js的執(zhí)行
- 有時候瀏覽器比較空閑,有可能一幀不需要 16ms,可能需要6ms, 那剩下的10ms可以執(zhí)行長任務(wù)
- 當剩下的10ms用完,可以把瀏覽器的渲染權(quán)利再還給瀏覽器
- 這個時候進入下一幀的瀏覽器的畫面,繼續(xù)渲染,渲染完之后又有剩余時間
- 接著再執(zhí)行這個長進程,簡單來說,就是把長進程拆分成一個個很小的任務(wù)
- 它利用瀏覽器每一幀的空閑時間去執(zhí)行,這樣就實現(xiàn)了任務(wù)的打斷,而且還不阻塞瀏覽器的渲染
- 也就是說,本來一個任務(wù)要執(zhí)行1秒,但是實際上react的fiber架構(gòu)可能讓這個1秒執(zhí)行的時間更長
- 因為任務(wù)的拆分其實是增加了這個計算的開銷的,但是,它卻是在我們每一幀的空閑時間去執(zhí)行的
- 雖然執(zhí)行的整體時間可能變長,但是讓用戶的感覺沒有那么卡頓,所以它的體驗是提升了的
- 參考之前 React 16的時間片:https://blog.csdn.net/Tyro_java/article/details/135586572
關(guān)于 requestIdleCallback
-
文檔:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback
-
window.requestIdleCallback() 方法插入一個函數(shù),這個函數(shù)將在瀏覽器空閑時期被調(diào)用
-
這使開發(fā)者能夠在主事件循環(huán)上執(zhí)行后臺和低優(yōu)先級工作,而不會影響延遲關(guān)鍵事件,如動畫和輸入響應(yīng)
-
函數(shù)一般會按先進先調(diào)用的順序執(zhí)行,然而,如果回調(diào)函數(shù)指定了執(zhí)行超時時間timeout,則有可能為了在超時前執(zhí)行函數(shù)而打亂執(zhí)行順序
-
requestIdleCallback(callback)
-
requestIdleCallback(callback, options)
- callback
- 一個在事件循環(huán)空閑時即將被調(diào)用的函數(shù)的引用。函數(shù)會接收到一個名為 IdleDeadline 的參數(shù)
- 這個參數(shù)可以獲取當前空閑時間以及回調(diào)是否在超時時間前已經(jīng)執(zhí)行的狀態(tài)
- options 可選
- 包括可選的配置參數(shù)。具有如下屬性
- timeout
- 如果指定了 timeout,并且有一個正值,而回調(diào)在 timeout 毫秒過后還沒有被調(diào)用
- 那么回調(diào)任務(wù)將放入事件循環(huán)中排隊,即使這樣做有可能對性能產(chǎn)生負面影響
- timeout
- 包括可選的配置參數(shù)。具有如下屬性
- callback
-
返回值是一個ID,可以把它傳入
Window.cancelIdleCallback()
方法來結(jié)束回調(diào)
requestIdleCallback 和 requestAnimationFrame 的區(qū)別
1 )react fiber 引起的關(guān)注
- 組件樹轉(zhuǎn)換為鏈表,可分段渲染
- 渲染時可以暫停,去執(zhí)行其他高優(yōu)先任務(wù),空閑時再繼續(xù)渲染
- 如何判斷空閑?requestIdleCallback
2 ) 區(qū)別
-
requestAnimationFrame 每次渲染完都會執(zhí)行,高優(yōu)
-
requestIdleCallback 空閑時才會執(zhí)行,低優(yōu)
let curWidth = 100 const maxWidth = 400function addWidth() {curWidth = curWidth + 3box.style.width = `${curWidth} px`if (curWidth < maxWidth) {widndow.requestAnimationFrame(addWidth) // 時間不用自己控制 高優(yōu)先級widndow.requestIdleCallback(addWidth) // 時間不用自己控制 繁忙時不會執(zhí)行} }addWidth()
-
對比
console.info('start') window.requestIdleCallback(()=>{console.log('requestIdleCallback') }) window.requestAnimationFrame(()=>{console.log('requestAnimationFrame') }) setTimeout(()=>{console.log('setTimeout') }) console.info('end')
-
執(zhí)行順序
- start
- end
- timeout 優(yōu)先級更高
- requestAnimationFrame 宏任務(wù)優(yōu)先級較高
- requestIdleCallback 宏任務(wù)優(yōu)先級較低
-
總結(jié)
- 兩者都是宏任務(wù)
- 需要等待dom渲染完才會執(zhí)行