網(wǎng)站首頁 編程語言 正文
React不使用requestIdleCallback實(shí)現(xiàn)調(diào)度原理解析_React
作者:用戶6816925221619 ? 更新時(shí)間: 2022-12-25 編程語言1.起因
最近在一邊啃源碼,一邊手寫fiber嘛,然后也看了很多博客和資料,基本上大伙好像都是說用requestIdleCallback來模擬react實(shí)現(xiàn)一個(gè)空閑時(shí)間調(diào)度。但我自己手寫的時(shí)候把怎么用怎么怪,老是感覺有什么地方不對(duì)勁而且是在調(diào)度過程中,可能是因?yàn)槲沂窍雽懗鰜韥硪粋€(gè)相對(duì)健全一點(diǎn)的模版方便我以后寫源碼的其他部分把,然后分析了一下所以有了這篇博客。
2.查找問題
1.requestIdleCallback是利用幀之間空閑時(shí)間來執(zhí)行JS,它是一個(gè)低優(yōu)先級(jí)的處理策略它給我的感覺就是做一些類似上報(bào)之類的操作,但實(shí)際上Fiber的構(gòu)建以及渲染內(nèi)容,并不算是一個(gè)低優(yōu)先級(jí)任務(wù)。
2.兼容性這個(gè)就總所周知了,這個(gè)api并不適合在生產(chǎn)環(huán)境上。
3.requestIdleCallback實(shí)際上是在布局和繪制之后,那意味在也許你在里面做的事情(可能是通過數(shù)據(jù)修改觸發(fā)dom修改)會(huì)重排。可以看看這個(gè)試驗(yàn)
3.解決問題
所以這時(shí)候我們就可以回到源碼中去看,react是怎么實(shí)現(xiàn)的,源碼地址。
核心調(diào)度實(shí)現(xiàn)
// 有執(zhí)行任務(wù)
if (scheduledHostCallback !== null) {
const currentTime = getCurrentTime();
// 計(jì)算一幀的過期時(shí)間點(diǎn)
deadline = currentTime + yieldInterval;
const hasTimeRemaining = true;
try {
// 執(zhí)行c回調(diào)
const hasMoreWork = scheduledHostCallback(
hasTimeRemaining,
currentTime,
);
// 執(zhí)行完該回調(diào)后, 判斷后續(xù)是否還有其他任務(wù)
if (!hasMoreWork) {
isMessageLoopRunning = false;
scheduledHostCallback = null;
} else {
// 還有其他任務(wù), 推進(jìn)進(jìn)入下一個(gè)宏任務(wù)隊(duì)列中
port.postMessage(null);
}
} catch (error) {
// If a scheduler task throws, exit the current browser task so the
// error can be observed.
port.postMessage(null);
throw error;
}
} else {
isMessageLoopRunning = false;
}
// Yielding to the browser will give it a chance to paint, so we can
// reset this.
// 重置狀態(tài)
needsPaint = false;
};
const channel = new MessageChannel();
// port2 發(fā)送
const port = channel.port2;
// port1 接收
channel.port1.onmessage = performWorkUntilDeadline;
// 在每一幀中執(zhí)行任務(wù)
requestHostCallback = function(callback) {
// 回調(diào)注冊(cè)
scheduledHostCallback = callback;
if (!isMessageLoopRunning) {
isMessageLoopRunning = true;
// 進(jìn)入宏任務(wù)隊(duì)列
port.postMessage(null);
}
};
// 取消回調(diào)
cancelHostCallback = function() {
scheduledHostCallback = null;
};
// 設(shè)置超時(shí)回調(diào)
requestHostTimeout = function(callback, ms) {
taskTimeoutID = setTimeout(() => {
callback(getCurrentTime());
}, ms);
};
// 取消超時(shí)
cancelHostTimeout = function() {
clearTimeout(taskTimeoutID);
taskTimeoutID = -1;
};
代碼里的注釋寫得很清楚了把,但有幾個(gè)點(diǎn)可以說一下。
1.首先選擇宏任務(wù),因?yàn)槲覀冃枰ゼ皶r(shí)的讓出主線程(微任務(wù)并不會(huì)讓出主線程也是在更新頁面前去執(zhí)行)。
2.其次是宏任務(wù)中的選擇,MessageChannel,setTimeout,requestAnimationFrame,都是宏任務(wù),setTimeout會(huì)浪費(fèi)4ms(這個(gè)大伙可以去看看),requestAnimationFrame的觸發(fā)時(shí)間是不穩(wěn)定的(可以看看瀏覽器的更新頁面機(jī)制),所以我猜想最后就選了MessageChannel把。
4.總結(jié)
其實(shí)到這思路也比較明了了,把React中為什么不使用requestIdleCallback理清楚,還順便把React的核心調(diào)度原理看了一下。
5.吐槽
唉,其實(shí)看源碼和手寫源碼完全是兩種感覺,更多的是體現(xiàn)在實(shí)現(xiàn)細(xì)節(jié)和代碼耦合性健壯性的問題,寫是怎么寫都行,但如何寫優(yōu)雅的方便人迭代的代碼就好燒腦。比如你就想實(shí)現(xiàn)一個(gè)fiber的大體思路就不難,但是如果想你在fiber上加hook,難度幾何飆升,基礎(chǔ)構(gòu)建和細(xì)節(jié)實(shí)現(xiàn)就很重要了,手寫肯定是不等于抄,還需要在里面加寫自己的想法和如何簡化的方案。
原文鏈接:https://juejin.cn/post/7170095557443551246
相關(guān)推薦
- 2022-07-11 pandas的排序、分組groupby及cumsum累計(jì)求和方式_python
- 2022-12-10 Android入門之日歷選擇與時(shí)間選擇組件的使用_Android
- 2022-07-18 C語言枚舉類型
- 2022-05-08 Python集合set的交集和并集操作方法_python
- 2022-10-05 C++淺析數(shù)據(jù)在內(nèi)存中如何存儲(chǔ)_C 語言
- 2022-07-21 Eslint代碼保存自動(dòng)格式化
- 2022-09-22 git-lfs 離線安裝
- 2022-06-12 Android開發(fā)之保存圖片到相冊(cè)的三種方法詳解_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支