摘要:在上面我們已經(jīng)知道瀏覽器是一幀一幀執(zhí)行的,在兩個(gè)執(zhí)行幀之間,主線程通常會(huì)有一小段空閑時(shí)間,可以在這個(gè)空閑期調(diào)用空閑期回調(diào),執(zhí)行一些任務(wù)。另外由于這些堆棧是可以自己控制的,所以可以加入并發(fā)或者錯(cuò)誤邊界等功能。
文章首發(fā)于個(gè)人博客前言
2016 年都已經(jīng)透露出來(lái)的概念,這都 9102 年了,我才開(kāi)始寫(xiě) Fiber 的文章,表示慚愧呀。不過(guò)現(xiàn)在好的是關(guān)于 Fiber 的資料已經(jīng)很豐富了,在寫(xiě)文章的時(shí)候參考資料比較多,比較容易深刻的理解。
React 作為我最喜歡的框架,沒(méi)有之一,我愿意花很多時(shí)間來(lái)好好的學(xué)習(xí)他,我發(fā)現(xiàn)對(duì)于學(xué)習(xí)一門(mén)框架會(huì)有四種感受,剛開(kāi)始沒(méi)使用過(guò),可能有一種很神奇的感覺(jué);然后接觸了,遇到了不熟悉的語(yǔ)法,感覺(jué)這是什么垃圾東西,這不是反人類(lèi)么;然后當(dāng)你熟悉了之后,真香,設(shè)計(jì)得挺好的,這個(gè)時(shí)候它已經(jīng)改變了你編程的思維方式了;再到后來(lái),看過(guò)他的源碼,理解他的設(shè)計(jì)之后,設(shè)計(jì)得確實(shí)好,感覺(jué)自己也能寫(xiě)一個(gè)的樣子。
所以我今年(對(duì),沒(méi)錯(cuò),就是一年)就是想完全的學(xué)透 React,所以開(kāi)了一個(gè) Deep In React 的系列,把一些新手在使用 API 的時(shí)候不知道為什么的點(diǎn),以及一些為什么有些東西要這么設(shè)計(jì)寫(xiě)出來(lái),與大家共同探討 React 的奧秘。
我的思路是自上而下的介紹,先理解整體的 Fiber 架構(gòu),然后再細(xì)挖每一個(gè)點(diǎn),所以這篇文章主要是談 Fiber 架構(gòu)的。
介紹在詳細(xì)介紹 Fiber 之前,先了解一下 Fiber 是什么,以及為什么 React 團(tuán)隊(duì)要話(huà)兩年時(shí)間重構(gòu)協(xié)調(diào)算法。
React 的核心思想內(nèi)存中維護(hù)一顆虛擬DOM樹(shù),數(shù)據(jù)變化時(shí)(setState),自動(dòng)更新虛擬 DOM,得到一顆新樹(shù),然后 Diff 新老虛擬 DOM 樹(shù),找到有變化的部分,得到一個(gè) Change(Patch),將這個(gè) Patch 加入隊(duì)列,最終批量更新這些 Patch 到 DOM 中。
React 16 之前的不足首先我們了解一下 React 的工作過(guò)程,當(dāng)我們通過(guò)render() 和 setState() 進(jìn)行組件渲染和更新的時(shí)候,React 主要有兩個(gè)階段:
調(diào)和階段(Reconciler):官方解釋。React 會(huì)自頂向下通過(guò)遞歸,遍歷新數(shù)據(jù)生成新的 Virtual DOM,然后通過(guò) Diff 算法,找到需要變更的元素(Patch),放到更新隊(duì)列里面去。
渲染階段(Renderer):遍歷更新隊(duì)列,通過(guò)調(diào)用宿主環(huán)境的API,實(shí)際更新渲染對(duì)應(yīng)元素。宿主環(huán)境,比如 DOM、Native、WebGL 等。
在協(xié)調(diào)階段階段,由于是采用的遞歸的遍歷方式,這種也被成為 Stack Reconciler,主要是為了區(qū)別 Fiber Reconciler 取的一個(gè)名字。這種方式有一個(gè)特點(diǎn):一旦任務(wù)開(kāi)始進(jìn)行,就無(wú)法中斷,那么 js 將一直占用主線程, 一直要等到整棵 Virtual DOM 樹(shù)計(jì)算完成之后,才能把執(zhí)行權(quán)交給渲染引擎,那么這就會(huì)導(dǎo)致一些用戶(hù)交互、動(dòng)畫(huà)等任務(wù)無(wú)法立即得到處理,就會(huì)有卡頓,非常的影響用戶(hù)體驗(yàn)。
如何解決之前的不足之前的問(wèn)題主要的問(wèn)題是任務(wù)一旦執(zhí)行,就無(wú)法中斷,js 線程一直占用主線程,導(dǎo)致卡頓。
可能有些接觸前端不久的不是特別理解上面為什么 js 一直占用主線程就會(huì)卡頓,我這里還是簡(jiǎn)單的普及一下。
瀏覽器每一幀都需要完成哪些工作?頁(yè)面是一幀一幀繪制出來(lái)的,當(dāng)每秒繪制的幀數(shù)(FPS)達(dá)到 60 時(shí),頁(yè)面是流暢的,小于這個(gè)值時(shí),用戶(hù)會(huì)感覺(jué)到卡頓。
1s 60 幀,所以每一幀分到的時(shí)間是 1000/60 ≈ 16 ms。所以我們書(shū)寫(xiě)代碼時(shí)力求不讓一幀的工作量超過(guò) 16ms。
瀏覽器一幀內(nèi)的工作
通過(guò)上圖可看到,一幀內(nèi)需要完成如下六個(gè)步驟的任務(wù):
處理用戶(hù)的交互
JS 解析執(zhí)行
幀開(kāi)始。窗口尺寸變更,頁(yè)面滾去等的處理
rAF(requestAnimationFrame)
布局
繪制
如果這六個(gè)步驟中,任意一個(gè)步驟所占用的時(shí)間過(guò)長(zhǎng),總時(shí)間超過(guò) 16ms 了之后,用戶(hù)也許就能看到卡頓。
而在上一小節(jié)提到的調(diào)和階段花的時(shí)間過(guò)長(zhǎng),也就是 js 執(zhí)行的時(shí)間過(guò)長(zhǎng),那么就有可能在用戶(hù)有交互的時(shí)候,本來(lái)應(yīng)該是渲染下一幀了,但是在當(dāng)前一幀里還在執(zhí)行 JS,就導(dǎo)致用戶(hù)交互不能麻煩得到反饋,從而產(chǎn)生卡頓感。
解決方案把渲染更新過(guò)程拆分成多個(gè)子任務(wù),每次只做一小部分,做完看是否還有剩余時(shí)間,如果有繼續(xù)下一個(gè)任務(wù);如果沒(méi)有,掛起當(dāng)前任務(wù),將時(shí)間控制權(quán)交給主線程,等主線程不忙的時(shí)候在繼續(xù)執(zhí)行。這種策略叫做 Cooperative Scheduling(合作式調(diào)度),操作系統(tǒng)常用任務(wù)調(diào)度策略之一。
補(bǔ)充知識(shí),操作系統(tǒng)常用任務(wù)調(diào)度策略:先來(lái)先服務(wù)(FCFS)調(diào)度算法、短作業(yè)(進(jìn)程)優(yōu)先調(diào)度算法(SJ/PF)、最高優(yōu)先權(quán)優(yōu)先調(diào)度算法(FPF)、高響應(yīng)比優(yōu)先調(diào)度算法(HRN)、時(shí)間片輪轉(zhuǎn)法(RR)、多級(jí)隊(duì)列反饋法。
合作式調(diào)度主要就是用來(lái)分配任務(wù)的,當(dāng)有更新任務(wù)來(lái)的時(shí)候,不會(huì)馬上去做 Diff 操作,而是先把當(dāng)前的更新送入一個(gè) Update Queue 中,然后交給 Scheduler 去處理,Scheduler 會(huì)根據(jù)當(dāng)前主線程的使用情況去處理這次 Update。為了實(shí)現(xiàn)這種特性,使用了requestIdelCallbackAPI。對(duì)于不支持這個(gè)API 的瀏覽器,React 會(huì)加上 pollyfill。
在上面我們已經(jīng)知道瀏覽器是一幀一幀執(zhí)行的,在兩個(gè)執(zhí)行幀之間,主線程通常會(huì)有一小段空閑時(shí)間,requestIdleCallback可以在這個(gè)空閑期(Idle Period)調(diào)用空閑期回調(diào)(Idle Callback),執(zhí)行一些任務(wù)。
低優(yōu)先級(jí)任務(wù)由requestIdleCallback處理;
高優(yōu)先級(jí)任務(wù),如動(dòng)畫(huà)相關(guān)的由requestAnimationFrame處理;
requestIdleCallback 可以在多個(gè)空閑期調(diào)用空閑期回調(diào),執(zhí)行任務(wù);
requestIdleCallback 方法提供 deadline,即任務(wù)執(zhí)行限制時(shí)間,以切分任務(wù),避免長(zhǎng)時(shí)間執(zhí)行,阻塞UI渲染而導(dǎo)致掉幀;
這個(gè)方案看似確實(shí)不錯(cuò),但是怎么實(shí)現(xiàn)可能會(huì)遇到幾個(gè)問(wèn)題:
如何拆分成子任務(wù)?
一個(gè)子任務(wù)多大合適?
怎么判斷是否還有剩余時(shí)間?
有剩余時(shí)間怎么去調(diào)度應(yīng)該執(zhí)行哪一個(gè)任務(wù)?
沒(méi)有剩余時(shí)間之前的任務(wù)怎么辦?
接下里整個(gè) Fiber 架構(gòu)就是來(lái)解決這些問(wèn)題的。
什么是 Fiber為了解決之前提到解決方案遇到的問(wèn)題,提出了以下幾個(gè)目標(biāo):
暫停工作,稍后再回來(lái)。
為不同類(lèi)型的工作分配優(yōu)先權(quán)。
重用以前完成的工作。
如果不再需要,則中止工作。
為了做到這些,我們首先需要一種方法將任務(wù)分解為單元。從某種意義上說(shuō),這就是 Fiber,F(xiàn)iber 代表一種工作單元。
但是僅僅是分解為單元也無(wú)法做到中斷任務(wù),因?yàn)楹瘮?shù)調(diào)用棧就是這樣,每個(gè)函數(shù)為一個(gè)工作,每個(gè)工作被稱(chēng)為堆棧幀,它會(huì)一直工作,直到堆棧為空,無(wú)法中斷。
所以我們需要一種增量渲染的調(diào)度,那么就需要重新實(shí)現(xiàn)一個(gè)堆棧幀的調(diào)度,這個(gè)堆棧幀可以按照自己的調(diào)度算法執(zhí)行他們。另外由于這些堆棧是可以自己控制的,所以可以加入并發(fā)或者錯(cuò)誤邊界等功能。
因此 Fiber 就是重新實(shí)現(xiàn)的堆棧幀,本質(zhì)上 Fiber 也可以理解為是一個(gè)虛擬的堆棧幀,將可中斷的任務(wù)拆分成多個(gè)子任務(wù),通過(guò)按照優(yōu)先級(jí)來(lái)自由調(diào)度子任務(wù),分段更新,從而將之前的同步渲染改為異步渲染。
所以我們可以說(shuō) Fiber 是一種數(shù)據(jù)結(jié)構(gòu)(堆棧幀),也可以說(shuō)是一種解決可中斷的調(diào)用任務(wù)的一種解決方案,它的特性就是時(shí)間分片(time slicing)和暫停(supense)。
如果了解協(xié)程的可能會(huì)覺(jué)得 Fiber 的這種解決方案,跟協(xié)程有點(diǎn)像(區(qū)別還是很大的),是可以中斷的,可以控制執(zhí)行順序。在 JS 里的 generator 其實(shí)就是一種協(xié)程的使用方式,不過(guò)顆粒度更小,可以控制函數(shù)里面的代碼調(diào)用的順序,也可以中斷。Fiber 是如何工作的
ReactDOM.render() 和 setState 的時(shí)候開(kāi)始創(chuàng)建更新。
將創(chuàng)建的更新加入任務(wù)隊(duì)列,等待調(diào)度。
在 requestIdleCallback 空閑時(shí)執(zhí)行任務(wù)。
從根節(jié)點(diǎn)開(kāi)始遍歷 Fiber Node,并且構(gòu)建 WokeInProgress Tree。
生成 effectList。
根據(jù) EffectList 更新 DOM。
下面是一個(gè)詳細(xì)的執(zhí)行過(guò)程圖:
第一部分從 ReactDOM.render() 方法開(kāi)始,把接收的 React Element 轉(zhuǎn)換為 Fiber 節(jié)點(diǎn),并為其設(shè)置優(yōu)先級(jí),創(chuàng)建 Update,加入到更新隊(duì)列,這部分主要是做一些初始數(shù)據(jù)的準(zhǔn)備。
第二部分主要是三個(gè)函數(shù):scheduleWork、requestWork、performWork,即安排工作、申請(qǐng)工作、正式工作三部曲,React 16 新增的異步調(diào)用的功能則在這部分實(shí)現(xiàn),這部分就是 Schedule 階段,前面介紹的 Cooperative Scheduling 就是在這個(gè)階段,只有在這個(gè)解決獲取到可執(zhí)行的時(shí)間片,第三部分才會(huì)繼續(xù)執(zhí)行。具體是如何調(diào)度的,后面文章再介紹,這是 React 調(diào)度的關(guān)鍵過(guò)程。
第三部分是一個(gè)大循環(huán),遍歷所有的 Fiber 節(jié)點(diǎn),通過(guò) Diff 算法計(jì)算所有更新工作,產(chǎn)出 EffectList 給到 commit 階段使用,這部分的核心是 beginWork 函數(shù),這部分基本就是 Fiber Reconciler ,包括 reconciliation 和 commit 階段。
Fiber NodeFIber Node,承載了非常關(guān)鍵的上下文信息,可以說(shuō)是貫徹整個(gè)創(chuàng)建和更新的流程,下來(lái)分組列了一些重要的 Fiber 字段。
{ ... // 跟當(dāng)前Fiber相關(guān)本地狀態(tài)(比如瀏覽器環(huán)境就是DOM節(jié)點(diǎn)) stateNode: any, // 單鏈表樹(shù)結(jié)構(gòu) return: Fiber | null,// 指向他在Fiber節(jié)點(diǎn)樹(shù)中的`parent`,用來(lái)在處理完這個(gè)節(jié)點(diǎn)之后向上返回 child: Fiber | null,// 指向自己的第一個(gè)子節(jié)點(diǎn) sibling: Fiber | null, // 指向自己的兄弟結(jié)構(gòu),兄弟節(jié)點(diǎn)的return指向同一個(gè)父節(jié)點(diǎn) // 更新相關(guān) pendingProps: any, // 新的變動(dòng)帶來(lái)的新的props memoizedProps: any, // 上一次渲染完成之后的props updateQueue: UpdateQueueFiber Reconciler| null, // 該Fiber對(duì)應(yīng)的組件產(chǎn)生的Update會(huì)存放在這個(gè)隊(duì)列里面 memoizedState: any, // 上一次渲染的時(shí)候的state // Scheduler 相關(guān) expirationTime: ExpirationTime, // 代表任務(wù)在未來(lái)的哪個(gè)時(shí)間點(diǎn)應(yīng)該被完成,不包括他的子樹(shù)產(chǎn)生的任務(wù) // 快速確定子樹(shù)中是否有不在等待的變化 childExpirationTime: ExpirationTime, // 在Fiber樹(shù)更新的過(guò)程中,每個(gè)Fiber都會(huì)有一個(gè)跟其對(duì)應(yīng)的Fiber // 我們稱(chēng)他為`current <==> workInProgress` // 在渲染完成之后他們會(huì)交換位置 alternate: Fiber | null, // Effect 相關(guān)的 effectTag: SideEffectTag, // 用來(lái)記錄Side Effect nextEffect: Fiber | null, // 單鏈表用來(lái)快速查找下一個(gè)side effect firstEffect: Fiber | null, // 子樹(shù)中第一個(gè)side effect lastEffect: Fiber | null, // 子樹(shù)中最后一個(gè)side effect .... };
在第二部分,進(jìn)行 Schedule 完,獲取到時(shí)間片之后,就開(kāi)始進(jìn)行 reconcile。
Fiber Reconciler 是 React 里的調(diào)和器,這也是任務(wù)調(diào)度完成之后,如何去執(zhí)行每個(gè)任務(wù),如何去更新每一個(gè)節(jié)點(diǎn)的過(guò)程,對(duì)應(yīng)上面的第三部分。
reconcile 過(guò)程分為2個(gè)階段(phase):
(可中斷)render/reconciliation 通過(guò)構(gòu)造 WorkInProgress Tree 得出 Change。
(不可中斷)commit 應(yīng)用這些DOM change。
reconciliation 階段在 reconciliation 階段的每個(gè)工作循環(huán)中,每次處理一個(gè) Fiber,處理完可以中斷/掛起整個(gè)工作循環(huán)。通過(guò)每個(gè)節(jié)點(diǎn)更新結(jié)束時(shí)向上歸并 Effect List 來(lái)收集任務(wù)結(jié)果,reconciliation 結(jié)束后,根節(jié)點(diǎn)的 Effect List里記錄了包括 DOM change 在內(nèi)的所有 Side Effect。
render 階段可以理解為就是 Diff 的過(guò)程,得出 Change(Effect List),會(huì)執(zhí)行聲明如下的聲明周期方法:
[UNSAFE_]componentWillMount(棄用)
[UNSAFE_]componentWillReceiveProps(棄用)
getDerivedStateFromProps
shouldComponentUpdate
[UNSAFE_]componentWillUpdate(棄用)
render
由于 reconciliation 階段是可中斷的,一旦中斷之后恢復(fù)的時(shí)候又會(huì)重新執(zhí)行,所以很可能 reconciliation 階段的生命周期方法會(huì)被多次調(diào)用,所以在 reconciliation 階段的生命周期的方法是不穩(wěn)定的,我想這也是 React 為什么要廢棄 componentWillMount 和 componentWillReceiveProps方法而改為靜態(tài)方法 getDerivedStateFromProps 的原因吧。
commit 階段commit 階段可以理解為就是將 Diff 的結(jié)果反映到真實(shí) DOM 的過(guò)程。
在 commit 階段,在 commitRoot 里會(huì)根據(jù) effect 的 effectTag,具體 effectTag 見(jiàn)源碼 ,進(jìn)行對(duì)應(yīng)的插入、更新、刪除操作,根據(jù) tag 不同,調(diào)用不同的更新方法。
commit 階段會(huì)執(zhí)行如下的聲明周期方法:
getSnapshotBeforeUpdate
componentDidMount
componentDidUpdate
componentWillUnmount
P.S:注意區(qū)別 reconciler、reconcile 和 reconciliation,reconciler 是調(diào)和器,是一個(gè)名詞,可以說(shuō)是 React 工作的一個(gè)模塊,協(xié)調(diào)模塊;reconcile 是調(diào)和器調(diào)和的動(dòng)作,是一個(gè)動(dòng)詞;而 reconciliation 只是 reconcile 過(guò)程的第一個(gè)階段。Fiber Tree 和 WorkInProgress Tree
React 在 render 第一次渲染時(shí),會(huì)通過(guò) React.createElement 創(chuàng)建一顆 Element 樹(shù),可以稱(chēng)之為 Virtual DOM Tree,由于要記錄上下文信息,加入了 Fiber,每一個(gè) Element 會(huì)對(duì)應(yīng)一個(gè) Fiber Node,將 Fiber Node 鏈接起來(lái)的結(jié)構(gòu)成為 Fiber Tree。它反映了用于渲染 UI 的應(yīng)用程序的狀態(tài)。這棵樹(shù)通常被稱(chēng)為 current 樹(shù)(當(dāng)前樹(shù),記錄當(dāng)前頁(yè)面的狀態(tài))。
在后續(xù)的更新過(guò)程中(setState),每次重新渲染都會(huì)重新創(chuàng)建 Element, 但是 Fiber 不會(huì),F(xiàn)iber 只會(huì)使用對(duì)應(yīng)的 Element 中的數(shù)據(jù)來(lái)更新自己必要的屬性,
Fiber Tree 一個(gè)重要的特點(diǎn)是鏈表結(jié)構(gòu),將遞歸遍歷編程循環(huán)遍歷,然后配合 requestIdleCallback API, 實(shí)現(xiàn)任務(wù)拆分、中斷與恢復(fù)。
這個(gè)鏈接的結(jié)構(gòu)是怎么構(gòu)成的呢,這就要主要到之前 Fiber Node 的節(jié)點(diǎn)的這幾個(gè)字段:
// 單鏈表樹(shù)結(jié)構(gòu) { return: Fiber | null, // 指向父節(jié)點(diǎn) child: Fiber | null,// 指向自己的第一個(gè)子節(jié)點(diǎn) sibling: Fiber | null,// 指向自己的兄弟結(jié)構(gòu),兄弟節(jié)點(diǎn)的return指向同一個(gè)父節(jié)點(diǎn) }
每一個(gè) Fiber Node 節(jié)點(diǎn)與 Virtual Dom 一一對(duì)應(yīng),所有 Fiber Node 連接起來(lái)形成 Fiber tree, 是個(gè)單鏈表樹(shù)結(jié)構(gòu),如下圖所示:
對(duì)照?qǐng)D來(lái)看,是不是可以知道 Fiber Node 是如何聯(lián)系起來(lái)的呢,F(xiàn)iber Tree 就是這樣一個(gè)單鏈表。
當(dāng) render 的時(shí)候有了這么一條單鏈表,當(dāng)調(diào)用 setState 的時(shí)候又是如何 Diff 得到 change 的呢?
采用的是一種叫雙緩沖技術(shù)(double buffering),這個(gè)時(shí)候就需要另外一顆樹(shù):WorkInProgress Tree,它反映了要刷新到屏幕的未來(lái)狀態(tài)。
WorkInProgress Tree 構(gòu)造完畢,得到的就是新的 Fiber Tree,然后喜新厭舊(把 current 指針指向WorkInProgress Tree,丟掉舊的 Fiber Tree)就好了。
這樣做的好處:
能夠復(fù)用內(nèi)部對(duì)象(fiber)
節(jié)省內(nèi)存分配、GC的時(shí)間開(kāi)銷(xiāo)
就算運(yùn)行中有錯(cuò)誤,也不會(huì)影響 View 上的數(shù)據(jù)
每個(gè) Fiber上都有個(gè)alternate屬性,也指向一個(gè) Fiber,創(chuàng)建 WorkInProgress 節(jié)點(diǎn)時(shí)優(yōu)先取alternate,沒(méi)有的話(huà)就創(chuàng)建一個(gè)。
創(chuàng)建 WorkInProgress Tree 的過(guò)程也是一個(gè) Diff 的過(guò)程,Diff 完成之后會(huì)生成一個(gè) Effect List,這個(gè) Effect List 就是最終 Commit 階段用來(lái)處理副作用的階段。
后記本開(kāi)始想一篇文章把 Fiber 講透的,但是寫(xiě)著寫(xiě)著發(fā)現(xiàn)確實(shí)太多了,想寫(xiě)詳細(xì),估計(jì)要寫(xiě)幾萬(wàn)字,所以我這篇文章的目的僅僅是在沒(méi)有涉及到源碼的情況下梳理了大致 React 的工作流程,對(duì)于細(xì)節(jié),比如如何調(diào)度異步任務(wù)、如何去做 Diff 等等細(xì)節(jié)將以小節(jié)的方式一個(gè)個(gè)的結(jié)合源碼進(jìn)行分析。
說(shuō)實(shí)話(huà),自己不是特別滿(mǎn)意這篇,感覺(jué)頭重腳輕,在講協(xié)調(diào)之前寫(xiě)得還挺好的,但是在講協(xié)調(diào)這塊文字反而變少了,因?yàn)槲沂菍?zhuān)門(mén)想寫(xiě)一篇文章講協(xié)調(diào)的,所以這篇僅僅用來(lái)梳理整個(gè)流程。
但是梳理整個(gè)流程又發(fā)現(xiàn) Schedule 這塊基本沒(méi)什么體現(xiàn),哎,不想寫(xiě)了,這篇文章拖太久了,請(qǐng)繼續(xù)后續(xù)的文章。
可以關(guān)注我的 github:Deep In React
一些問(wèn)題接下來(lái)留一些思考題。
如何去劃分任務(wù)優(yōu)先級(jí)?
在 reconcile 過(guò)程的 render 階段是如何去遍歷鏈表,如何去構(gòu)建 workInProgress 的?
當(dāng)任務(wù)被打斷,如何恢復(fù)?
如何去收集 EffectList?
針對(duì)不同的組件類(lèi)型如何進(jìn)行更新?
參考完全理解 React Fiber)
Fiber
React16源碼之React Fiber架構(gòu)
我是桃翁,一個(gè)愛(ài)思考的前端er,想了解關(guān)于更多的前端相關(guān)的,請(qǐng)關(guān)注我的公號(hào):「前端桃園」
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/105036.html
摘要:因?yàn)榘姹緦⒄嬲龔U棄這三生命周期到目前為止,的渲染機(jī)制遵循同步渲染首次渲染,更新時(shí)更新時(shí)卸載時(shí)期間每個(gè)周期函數(shù)各司其職,輸入輸出都是可預(yù)測(cè),一路下來(lái)很順暢。通過(guò)進(jìn)一步觀察可以發(fā)現(xiàn),預(yù)廢棄的三個(gè)生命周期函數(shù)都發(fā)生在虛擬的構(gòu)建期間,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段時(shí)間準(zhǔn)備前端招聘事項(xiàng)...
摘要:毫無(wú)疑問(wèn),作為近兩年前端三大流行框架之一,正成為程序員們最喜愛(ài)的框架。自年月開(kāi)源至今,已有千萬(wàn)網(wǎng)站使用來(lái)進(jìn)行前端構(gòu)架,使之成為最受歡迎的項(xiàng)目之一。經(jīng)過(guò)這幾年的沉淀,越來(lái)越強(qiáng)大,暫不提這幾年在國(guó)內(nèi)與之間的矛盾,這其中還有很大談判空間。 showImg(https://segmentfault.com/img/bV0dY9?w=469&h=240); React在國(guó)外已被各個(gè)公司的各種產(chǎn)品...
摘要:對(duì)于同一層級(jí)的一組子節(jié)點(diǎn),它們可以通過(guò)唯一進(jìn)行區(qū)分?;谝陨先齻€(gè)前提策略,分別對(duì)以及進(jìn)行算法優(yōu)化。鏈表的每一個(gè)節(jié)點(diǎn)是,而不是在之前的虛擬節(jié)點(diǎn)。是當(dāng)前層的第一個(gè)節(jié)點(diǎn)。再次提醒,是的一層。 文章首發(fā)于個(gè)人博客 這是我 Deep In React 系列的第二篇文章,如果還沒(méi)有讀過(guò)的強(qiáng)烈建議你先讀第一篇:詳談 React Fiber 架構(gòu)(1)。 前言 我相信在看這篇文章的讀者一般都已經(jīng)了解...
摘要:架構(gòu)理解引用原文是核心算法正在進(jìn)行的重新實(shí)現(xiàn)。構(gòu)建的過(guò)程就是的過(guò)程,通過(guò)來(lái)調(diào)度執(zhí)行一組任務(wù),每完成一個(gè)任務(wù)后回來(lái)看看有沒(méi)有插隊(duì)的更緊急的,把時(shí)間控制權(quán)交還給主線程,直到下一次回調(diào)再繼續(xù)構(gòu)建。 React Fiber 架構(gòu)理解 引用原文:React Fiber ArchitectureReact Fiber is an ongoing reimplementation of Reacts...
摘要:什么是每一個(gè)都有一個(gè)對(duì)應(yīng)的,記錄這個(gè)節(jié)點(diǎn)的各種狀態(tài),是一鏈表的結(jié)構(gòu)的串聯(lián)起來(lái)。 1. 什么是fiber 每一個(gè)ReactElement都有一個(gè)對(duì)應(yīng)的fiber, 記錄這個(gè)節(jié)點(diǎn)的各種狀態(tài), fiber是一鏈表的結(jié)構(gòu)的串聯(lián)起來(lái)。showImg(https://segmentfault.com/img/bVbqVZR?w=540&h=708); 2. Fiber的組成 export type...
閱讀 3499·2021-11-25 09:43
閱讀 1103·2021-11-15 11:36
閱讀 3346·2021-11-11 16:54
閱讀 4011·2021-09-27 13:35
閱讀 4404·2021-09-10 11:23
閱讀 6162·2021-09-07 10:22
閱讀 3071·2021-09-04 16:40
閱讀 800·2021-08-03 14:03