談?wù)剅eact fiber

react fiber
react fiber是16版本之后的一種更新機(jī)制,使用鏈表取代了樹,是一種fiber數(shù)據(jù)結(jié)構(gòu),其有三個(gè)指針,分別指向了父節(jié)點(diǎn)、子節(jié)點(diǎn)、兄弟節(jié)點(diǎn),當(dāng)中斷的時(shí)候會(huì)記錄下當(dāng)前的節(jié)點(diǎn),然后繼續(xù)更新,而15版本中的DOM stack不能有中斷操作,它把組件渲染的工作分片,到時(shí)會(huì)主動(dòng)讓出渲染主線程。
react因?yàn)闊o(wú)法做到跟vue一樣精準(zhǔn)更新,因?yàn)関ue底層是用object.defineProperty(),通過(guò)setter、getter對(duì)數(shù)據(jù)做劫持,結(jié)合發(fā)布訂閱者模式通知數(shù)據(jù)更新,從而更新視圖,所以react采用了fiber鏈表的數(shù)據(jù)結(jié)構(gòu),使得將組件渲染工作分片,讓出主線程做交互響應(yīng),為了防止渲染抖動(dòng),會(huì)一次性commit將更新部分渲染好

簡(jiǎn)單的說(shuō):

  • 首次渲染的時(shí)候會(huì)生成跟虛擬DOM樹一樣結(jié)構(gòu)的fiber樹
  • 組件更新的時(shí)候,遍歷新舊fiber樹,diff區(qū)別,diff操作是分片進(jìn)行的,16ms內(nèi)如果沒(méi)有完成,就先暫停等待下一次渲染間隙再繼續(xù)
  • diff完成之后進(jìn)行commit,提交差異的部分,進(jìn)行對(duì)應(yīng)的dom操作,為了防止渲染抖動(dòng),commit是一次性完成的

diff過(guò)程:

對(duì)比新舊VNode是否相同節(jié)點(diǎn)(節(jié)點(diǎn)的key和sel相同)
如果不是相同節(jié)點(diǎn),刪除之前的內(nèi)容,重新渲染
如果是相同節(jié)點(diǎn),再判斷新的VNode是否有text,如果有并且和oldVnode的text不同直接更新文本內(nèi)容(patchVnode)
如果新的VNode有children,判斷子節(jié)點(diǎn)是否有變化(updateChildren,最麻煩,最難實(shí)現(xiàn))

diff算法fiber過(guò)程:

如果是更新階段,就先判斷有沒(méi)有老 Fiber 節(jié)點(diǎn),如果沒(méi)有老 Fiber 節(jié)點(diǎn),則說(shuō)明該節(jié)點(diǎn)需要?jiǎng)?chuàng)建,就給當(dāng)前新的 Fiber 節(jié)點(diǎn)打上一個(gè) Placement 的標(biāo)記,如果有老 Fiber 節(jié)點(diǎn),則判斷老 Fiber 節(jié)點(diǎn)的位置是否比上一次協(xié)調(diào)的返回的位置小,如果是,則說(shuō)明該節(jié)點(diǎn)需要移動(dòng),給新 Fiber 節(jié)點(diǎn)打上一個(gè) Placement 的標(biāo)記,并繼續(xù)返回上一次協(xié)調(diào)返回的位置;如果老 Fiber 節(jié)點(diǎn)的位置大或者等于上一次協(xié)調(diào)返回的位置,則說(shuō)明該節(jié)點(diǎn)不需要進(jìn)行位置移動(dòng)操作,就返回老 Fiber 的位置即可。

這里需要說(shuō)明的一點(diǎn),為什么移動(dòng)和新增節(jié)點(diǎn)都是 Placement 的標(biāo)記呢?

因?yàn)槲覀兪窃趨f(xié)調(diào)一個(gè)子節(jié)點(diǎn)列表,所以不管是新增還是移動(dòng)都是屬于位置是需要發(fā)生變化的,所以新增和移動(dòng)都是同一種操作情況。

總個(gè)來(lái)說(shuō),React Diff 算法分以下幾個(gè)步驟:

第一輪,從左向右新老節(jié)點(diǎn)進(jìn)行比對(duì)查找能復(fù)用的舊節(jié)點(diǎn),如果有新老節(jié)點(diǎn)比對(duì)不成功的,則停止這一輪的比對(duì),并記錄了停止的位置。
如果第一輪比對(duì),能把所有的新節(jié)點(diǎn)都比對(duì)完畢,則刪除舊節(jié)點(diǎn)還沒(méi)進(jìn)行比對(duì)的節(jié)點(diǎn)。
如果第一輪的比對(duì),沒(méi)能將所有的新節(jié)點(diǎn)都比對(duì)完畢,則繼續(xù)從第一輪比對(duì)停止的位置繼續(xù)開(kāi)始循環(huán)新節(jié)點(diǎn),拿每一個(gè)新節(jié)點(diǎn)去老節(jié)點(diǎn)里面進(jìn)行查找,有匹配成功的則復(fù)用,沒(méi)匹配成功的則在協(xié)調(diào)位置的時(shí)候打上 Placement 的標(biāo)記。
在所有新節(jié)點(diǎn)比對(duì)完畢之后,檢查還有沒(méi)有沒(méi)進(jìn)行復(fù)用的舊節(jié)點(diǎn),如果有,則全部刪除。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容