<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
React 是基於 vdom 的前端框架,元件 render 產生 vdom,然後渲染器把 vdom 渲染出來。
state 更新的時候,元件會重新 render,產生新的 vdom,在瀏覽器平臺下,為了減少 dom 的建立,React 會對兩次的 render 結果做 diff,儘量複用 dom,提高效能。
diff 演演算法是前端框架中比較複雜的部分,程式碼比較多,但今天我們不上程式碼,只看圖來理解它。
首先,我們先過一下 react 的 fiber 架構:
React 是通過 jsx 描述頁面結構的:
const profile = { return <div> <img src="avatar.png" className="profile" /> <h3>{[user.firstName, user.lastName].join(" ")}</h3> </div>
經過 babel 等的編譯會變成 render function:
import { jsx as _jsx } from "react/jsx-runtime"; import { jsxs as _jsxs } from "react/jsx-runtime"; const profile = _jsxs("div", { children: [ _jsx("img", { src: "avatar.png", className: "profile", }), _jsx("h3", { children: [user.firstName, user.lastName].join(" "), }), ], });
render function 執行結果就是 vdom,也就是 React Element 的範例:
在 16 之前,React 是直接遞迴渲染 vdom 的,setState 會觸發重新渲染,對比渲染出的新舊 vdom,對差異部分進行 dom 操作。
在 16 之後,為了優化效能,會先把 vdom 轉換成 fiber,也就是從樹轉換成連結串列,然後再渲染。整體渲染流程分成了兩個階段:
從 vdom 轉成 fiber 的過程叫做 reconcile(調和),這個過程是可以打斷的,由 scheduler 排程執行。
diff 演演算法作用在 reconcile 階段:
第一次渲染不需要 diff,直接 vdom 轉 fiber。
再次渲染的時候,會產生新的 vdom,這時候要和之前的 fiber 做下對比,決定怎麼產生新的 fiber,對可複用的節點打上修改的標記,剩餘的舊節點打上刪除標記,新節點打上新增標記。
接下來我們就來詳細瞭解下 React 的 diff 演演算法:
在講 diff 演演算法實現之前,我們要先想明白為什麼要做 diff,不做行麼?
當然可以,每一次渲染都直接把 vdom 轉成 fiber 就行,不用和之前的做對比,這樣是可行的。
其實 SSR 的時候就不用做 diff,因為會把元件渲染成字串,第二次渲染也是產生字串,難道這時候還要和之前的字串對比下,有哪些字串可以複用麼?
不需要,SSR 的時候就沒有 diff,每次都是 vdom 渲染出新的字串。
那為什麼瀏覽器裡要做 diff 呢?
因為 dom 建立的效能成本很高,如果不做 dom 的複用,那前端框架的效能就太差了。
diff 演演算法的目的就是對比兩次渲染結果,找到可複用的部分,然後剩下的該刪除刪除,該新增新增。
那具體怎麼實現 React 的 diff 演演算法呢?
比如父節點下有 A、B、C、D 四個子節點,那渲染出的 vdom 就是這樣的:
經過 reconcile 之後,會變成這樣的 fiber 結構:
那如果再次渲染的時候,渲染出了 A、C、B、E 的 vdom,這時候怎麼處理呢?
再次渲染出 vdom 的時候,也要進行 vdom 轉 fiber 的 reconcile 階段,但是要儘量能複用之前的節點。
那怎麼複用呢?
一一對比下不就行了?
先把之前的 fiber 節點放到一個 map 裡,key 就是節點的 key:
然後每個新的 vdom 都去這個 map 裡查詢下有沒有可以複用的,找到了的話就移動過來,打上更新的 effectTag:
這樣遍歷完 vdom 節點之後,map 裡剩下一些,這些是不可複用的,那就刪掉,打上刪除的 effectTag;如果 vdom 中還有一些沒找到複用節點的,就直接建立,打上新增的 effectTag。
這樣就實現了更新時的 reconcile,也就是上面的 diff 演演算法。其實核心就是找到可複用的節點,剩下的舊節點刪掉,新節點新增。
但有的時候可以再簡化一下,比如上次渲染是 A、B、C、D,這次渲染也是 A、B、C、D,那直接順序對比下就行,沒必要建立 map 再找。
所以 React 的 diff 演演算法是分成兩次遍歷的:
第一輪遍歷,一一對比 vdom 和老的 fiber,如果可以複用就處理下一個節點,否則就結束遍歷。
如果所有的新的 vdom 處理完了,那就把剩下的老 fiber 節點刪掉就行。
如果還有 vdom 沒處理,那就進行第二次遍歷:
第二輪遍歷,把剩下的老 fiber 放到 map 裡,遍歷剩下的 vdom,從 map 裡查詢,如果找到了,就移動過來。
第二輪遍歷完了之後,把剩餘的老 fiber 刪掉,剩餘的 vdom 新增。
這樣就完成了新的 fiber 結構的建立,也就是 reconcile 的過程。
比如上面那個例子,第一輪遍歷就是這樣的:
一一對比新的 vdom 和 老的 fiber,發現 A 是可以複用的,那就建立新 fiber 節點,打上更新標記。
C 不可複用,所以結束第一輪遍歷,進入第二輪遍歷。
把剩下的 老 fiber 節點放到 map 裡,然後遍歷新的 vdom 節點,從 map 中能找到的話,就是可複用,移動過來打上更新的標記。
遍歷完之後,剩下的老 fiber 節點刪掉,剩下的新 vdom 新增。
這樣就完成了更新時的 reconcile 的過程。
react 是基於 vdom 的前端框架,元件渲染產生 vdom,渲染器把 vdom 渲染成 dom。
瀏覽器下使用 react-dom 的渲染器,會先把 vdom 轉成 fiber,找到需要更新 dom 的部分,打上增刪改的 effectTag 標記,這個過程叫做 reconcile,可以打斷,由 scheducler 排程執行。reconcile 結束之後一次性根據 effectTag 更新 dom,叫做 commit。
這就是 react 的基於 fiber 的渲染流程,分成 render(reconcile + schedule)、commit 兩個階段。
當渲染完一次,產生了 fiber 之後,再次渲染的 vdom 要和之前的 fiber 對比下,再決定如何產生新的 fiber,目標是儘可能複用已有的 fiber 節點,這叫做 diff 演演算法。
react 的 diff 演演算法分為兩個階段:
第一個階段一一對比,如果可以複用就下一個,不可以複用就結束。
第二個階段把剩下的老 fiber 放到 map 裡,遍歷剩餘的 vdom,一一查詢 map 中是否有可複用的節點。
最後把剩下的老 fiber 刪掉,剩下的新 vdom 新增。
這樣就完成了更新時的 reconcile 過程。
其實 diff 演演算法的核心就是複用節點,通過一一對比也好,通過 map 查詢也好,都是為了找到可複用的節點,移動過來。然後剩下的該刪刪該增增。
理解了如何找到可複用的節點,就理解了 diff 演演算法的核心。
以上就是 React的diff演演算法核心複用詳解的詳細內容,更多關於React diff 演演算法複用的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45