react源碼解析7.Fiber架構(gòu)
視頻課程(高效學(xué)習(xí)):進(jìn)入課程
課程目錄:
6.legacy和concurrent模式入口函數(shù)
Fiber的深度理解
react15在render階段的reconcile是不可打斷的善已,這會在進(jìn)行大量節(jié)點(diǎn)的reconcile時可能產(chǎn)生卡頓擎椰,因?yàn)闉g覽器所有的時間都交給了js執(zhí)行,并且js的執(zhí)行時單線程脐嫂。為此react16之后就有了scheduler進(jìn)行時間片的調(diào)度,給每個task(工作單元)一定的時間艳吠,如果在這個時間內(nèi)沒執(zhí)行完队丝,也要交出執(zhí)行權(quán)給瀏覽器進(jìn)行繪制和重排,所以異步可中斷的更新需要一定的數(shù)據(jù)結(jié)構(gòu)在內(nèi)存中來保存工作單元的信息呢堰,這個數(shù)據(jù)結(jié)構(gòu)就是Fiber。
那么有了Fiber這種數(shù)據(jù)結(jié)構(gòu)后凡泣,能完成哪些事情呢枉疼,
- 工作單元 任務(wù)分解 :Fiber最重要的功能就是作為工作單元皮假,保存原生節(jié)點(diǎn)或者組件節(jié)點(diǎn)對應(yīng)信息(包括優(yōu)先級),這些節(jié)點(diǎn)通過指針的形似形成Fiber樹
- 增量渲染:通過jsx對象和current Fiber的對比骂维,生成最小的差異補(bǔ)丁惹资,應(yīng)用到真實(shí)節(jié)點(diǎn)上
- 根據(jù)優(yōu)先級暫停、繼續(xù)航闺、排列優(yōu)先級:Fiber節(jié)點(diǎn)上保存了優(yōu)先級褪测,能通過不同節(jié)點(diǎn)優(yōu)先級的對比,達(dá)到任務(wù)的暫停来颤、繼續(xù)汰扭、排列優(yōu)先級等能力稠肘,也為上層實(shí)現(xiàn)批量更新福铅、Suspense提供了基礎(chǔ)
- 保存狀態(tài):因?yàn)镕iber能保存狀態(tài)和更新的信息,所以就能實(shí)現(xiàn)函數(shù)組件的狀態(tài)更新项阴,也就是hooks
Fiber的數(shù)據(jù)結(jié)構(gòu)
Fiber的自帶的屬性如下:
//ReactFiber.old.js
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
//作為靜態(tài)的數(shù)據(jù)結(jié)構(gòu) 保存節(jié)點(diǎn)的信息
this.tag = tag;//對應(yīng)組件的類型
this.key = key;//key屬性
this.elementType = null;//元素類型
this.type = null;//func或者class
this.stateNode = null;//真實(shí)dom節(jié)點(diǎn)
//作為fiber數(shù)架構(gòu) 連接成fiber樹
this.return = null;//指向父節(jié)點(diǎn)
this.child = null;//指向child
this.sibling = null;//指向兄弟節(jié)點(diǎn)
this.index = 0;
this.ref = null;
//用作為工作單元 來計(jì)算state
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
//effect相關(guān)
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
//優(yōu)先級相關(guān)的屬性
this.lanes = NoLanes;
this.childLanes = NoLanes;
//current和workInProgress的指針
this.alternate = null;
}
Fiber雙緩存
現(xiàn)在我們知道了Fiber可以保存真實(shí)的dom滑黔,真實(shí)dom對應(yīng)在內(nèi)存中的Fiber節(jié)點(diǎn)會形成Fiber樹,這顆Fiber樹在react中叫current Fiber环揽,也就是當(dāng)前dom樹對應(yīng)的Fiber樹略荡,而正在構(gòu)建Fiber樹叫workInProgress Fiber,這兩顆樹的節(jié)點(diǎn)通過alternate相連.
function App() {
return (
<>
<h1>
<p>count</p> xiaochen
</h1>
</>
)
}
ReactDOM.render(<App />, document.getElementById("root"));
構(gòu)建workInProgress Fiber發(fā)生在createWorkInProgress中歉胶,它能創(chuàng)建或者服用Fiber
//ReactFiber.old.js
export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
let workInProgress = current.alternate;
if (workInProgress === null) {//區(qū)分是在mount時還是在update時
workInProgress = createFiber(
current.tag,
pendingProps,
current.key,
current.mode,
);
workInProgress.elementType = current.elementType;
workInProgress.type = current.type;
workInProgress.stateNode = current.stateNode;
workInProgress.alternate = current;
current.alternate = workInProgress;
} else {
workInProgress.pendingProps = pendingProps;//復(fù)用屬性
workInProgress.type = current.type;
workInProgress.flags = NoFlags;
workInProgress.nextEffect = null;
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
//...
}
workInProgress.childLanes = current.childLanes;//復(fù)用屬性
workInProgress.lanes = current.lanes;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
const currentDependencies = current.dependencies;
workInProgress.dependencies =
currentDependencies === null
? null
: {
lanes: currentDependencies.lanes,
firstContext: currentDependencies.firstContext,
};
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
return workInProgress;
}
-
在mount時:會創(chuàng)建fiberRoot和rootFiber汛兜,然后根據(jù)jsx對象創(chuàng)建Fiber節(jié)點(diǎn),節(jié)點(diǎn)連接成current Fiber樹通今。
-
在update時:會根據(jù)新的狀態(tài)形成的jsx(ClassComponent的render或者FuncComponent的返回值)和current Fiber對比形(diff算法)成一顆叫workInProgress的Fiber樹粥谬,然后將fiberRoot的current指向workInProgress樹,此時workInProgress就變成了current Fiber辫塌。fiberRoot:指整個應(yīng)用的根節(jié)點(diǎn)漏策,只存在一個
fiberRoot:指整個應(yīng)用的根節(jié)點(diǎn),只存在一個
rootFiber:ReactDOM.render或者ReactDOM.unstable_createRoot創(chuàng)建出來的應(yīng)用的節(jié)點(diǎn)臼氨,可以存在多個掺喻。
我們現(xiàn)在知道了存在current Fiber和workInProgress Fiber兩顆Fiber樹,F(xiàn)iber雙緩存指的就是储矩,在經(jīng)過reconcile(diff)形成了新的workInProgress Fiber然后將workInProgress Fiber切換成current Fiber應(yīng)用到真實(shí)dom中感耙,存在雙Fiber的好處是在內(nèi)存中形成視圖的描述,在最后應(yīng)用到dom中持隧,減少了對dom的操作抑月。
現(xiàn)在來看看Fiber雙緩存創(chuàng)建的過程圖:
-
mount時:
-
剛開始只創(chuàng)建了fiberRoot和rootFiber兩個節(jié)點(diǎn)
-
然后根據(jù)jsx創(chuàng)建workInProgress Fiber:
-
把workInProgress Fiber切換成current Fiber
-
-
update時
-
根據(jù)current Fiber創(chuàng)建workInProgress Fiber
- 把workInProgress Fiber切換成current Fiber
-