網站首頁 編程語言 正文
異步調度
問題:由于對于大型的 React 應用,會存在一次更新,遞歸遍歷大量的虛擬 DOM ,造成占用 js 線程,使得瀏覽器沒有時間去做一些動畫效果,伴隨項目越來越大,項目會越來越卡。
對比Vue:
Vue 有這 template 模版收集依賴的過程,輕松構建響應式,使得在一次更新中,Vue 能夠迅速響應,找到需要更新的范圍,然后以組件粒度更新組件,渲染視圖。
React 中,一次更新 React 無法知道此次更新的波及范圍,所以 React 選擇從根節點開始 diff ,查找不同,更新這些不同。
解決:
把 React 的更新,交給瀏覽器自己控制,瀏覽器先執行繪制任務,空閑時間執行更新任務,解決了卡頓問題。即采用異步調度的方法。
時間分片
React讓瀏覽器控制React更新:瀏覽器每執行一次事件循環都會:處理事件,執行 js,調用requestAnimation
,布局 Layout,繪制 Paint,在一次執行后,瀏覽器進入空閑時,可以執行更新任務
谷歌瀏覽器提供的一個 API, 在瀏覽器有空余的時間,瀏覽器就會調用 requestIdleCallback 的回調。
requestIdleCallback(callback,{ timeout })
- callback 回調。瀏覽器空余時間執行回調函數。
- timeout 超時時間。如果瀏覽器長時間沒有空閑,那么回調就不會執行,為了解決這個問題,可以通過 requestIdleCallback 的第二個參數指定一個超時時間。
React 為了防止 requestIdleCallback
中的任務由于瀏覽器沒有空閑時間而卡死,所以設置了 5 個優先級。
-
Immediate
-1 需要立刻執行。 -
UserBlocking
250ms 超時時間250ms,一般指的是用戶交互。 -
Normal
5000ms 超時時間5s,不需要直觀立即變化的任務,比如網絡請求。 -
Low
10000ms 超時時間10s,肯定要執行的任務,但是可以放在最后處理。 -
Idle
一些沒有必要的任務,可能不會執行。
模擬requestdleCallback
條件:
- 可以主動讓出主線程,讓瀏覽器去渲染視圖。
- 一次事件循環只執行一次,因為執行一個以后,還會請求下一次的時間片。
宏任務:在下次事件循環中執行,不會阻塞瀏覽器更新。且瀏覽器一次只會執行一個宏任務。
1、采用setTimeout(fn, 0),間隔時間會變成 4 毫秒左右,不是最優選方案
2、采用MessageChannel 接口,允許開發者創建一個新的消息通道,并通過它的兩個 MessagePort 屬性發送數據。
在一次更新中,向瀏覽器請求執行更新任務,調用 requesetHostCallbcak
,將更新任務 函數callback賦值給 scheduleHostCallback
,port2 向 port1 發起 postMessage消息通知。
port1 會通過 onmessage,接受來自 port2 消息,執行更新任務 scheduleHostCallback
,執行完后,清空任務。
異步調度原理
React 發生一次更新,會統一走 ensureRootIsScheduled(調度應用)
對于 正常更新 會走 performSyncWorkOnRoot 邏輯,最后會走 workLoopSync
。
對于 低優先級的異步更新 會走 performConcurrentWorkOnRoot 邏輯,最后會走 workLoopConcurrent
。
區別:異步模式會調用一個 shouldYield()
,如果當前瀏覽器沒有空余時間, shouldYield 會中止循環,直到瀏覽器有空閑時間后再繼續遍歷,從而達到終止渲染的目的。解決了一次性遍歷大量的 fiber ,導致瀏覽器沒有時間執行一些渲染任務,導致了頁面卡頓。
1、scheduleCallback
更新任務、異步更新任務都是由調度器 scheduleCallback
統一調度的
正常更新任務:
scheduleCallback(Immediate,workLoopSync)
異步更新任務:
/* 計算超時等級,就是如上那五個等級 */ var priorityLevel = inferPriorityFromExpirationTime(currentTime, expirationTime); scheduleCallback(priorityLevel,workLoopConcurrent)
scheduleCallback()
函數執行過程
scheduleCallback 流程如下:
- 創建一個新的任務 newTask。
- 通過任務的開始時間( startTime ) 和 當前時間( currentTime ) 比較:當 startTime > currentTime, 說明未過期,存到 timerQueue,當 startTime <= currentTime,說明已過期, 存到 taskQueue。
- 如果任務沒有過期,用
requestHostTimeout
延時執行handleTimeout
。 - 如果任務過期,并且沒有調度中的任務,那么調度
requestHostCallback
。 - 本質上調度的是
flushWork
。
2、requestHostTimeout
通過 setTimeout 來進行延時指定時間的。
延時執行 handleTimeout
,cancelHostTimeout
用于清除當前的延時器。
3、handleTimeout
延時時間后,handleTimeout 會把任務重新放在 requestHostCallback 調度。
通過 advanceTimers
將 timerQueue 中過期的任務轉移到 taskQueue 中。然后調用 requestHostCallback
調度過期的任務。
4、advanceTimers
如果任務已經過期,那么將 timerQueue 中的過期任務,放入 taskQueue。
5、flushWork
requestHostCallback ,放入 MessageChannel 中的回調函數是flushWork。
flushWork 如果有延時任務執行的話,那么會先暫停延時任務,然后調用 workLoop
,去真正執行超時的更新任務。
6、workLoop
workLoop 是調度中的 workLoop
React 的更新任務最后都是放在 taskQueue 中
workLoop 會依次更新過期任務隊列中的任務
調度流程圖
總結
1、異步調度原因
2、時間分片和 requestIdleCallback
3、異步調度原理
4、調度流程
原文鏈接:https://blog.csdn.net/weixin_45654582/article/details/122634214
相關推薦
- 2023-01-06 Flutter?Recovering?Stream?Errors小技巧_Android
- 2022-08-19 python項目中requirements.txt的用法實例教程_python
- 2022-12-11 C語言如何計算兩個數的最小公倍數_C 語言
- 2022-05-04 R語言數據類型與相應運算的實現_R語言
- 2022-10-07 C語言折半查找法介紹及使用示例_C 語言
- 2023-01-19 GO的基礎知識掃盲注意事項_Golang
- 2024-03-07 使用JdbcTemplate和Druid技術簡化持久層的編寫
- 2023-01-30 delphi?判斷字符串是否為純字母組合的函數_Delphi
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支