成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

圖解 React 的 Diff 算法:核心就兩個字 — 復用

開發 前端
React 是基于 Vdom 的前端框架,組件渲染產生 Vdom,渲染器把 Vdom 渲染成 Dom。

React 是基于 vdom 的前端框架,組件 render 產生 vdom,然后渲染器把 vdom 渲染出來。

state 更新的時候,組件會重新 render,產生新的 vdom,在瀏覽器平臺下,為了減少 dom 的創建,React 會對兩次的 render 結果做 diff,盡量復用 dom,提高性能。

diff 算法是前端框架中比較復雜的部分,代碼比較多,但今天我們不上代碼,只看圖來理解它。

首先,我們先過一下 react 的 fiber 架構:

Fiber 架構

React 是通過 jsx 描述頁面結構的:

function 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,也就是從樹轉換成鏈表,然后再渲染。整體渲染流程分成了兩個階段:

  • render 階段:從 vdom 轉換成 fiber,并且對需要 dom 操作的節點打上 effectTag 的標記。
  • commit 階段:對有 effectTag 標記的 fiber 節點進行 dom 操作,并執行所有的 effect 副作用函數。

從 vdom 轉成 fiber 的過程叫做 reconcile(調和),這個過程是可以打斷的,由 scheduler 調度執行。

圖片圖片

diff 算法作用在 reconcile 階段:

第一次渲染不需要 diff,直接 vdom 轉 fiber。

再次渲染的時候,會產生新的 vdom,這時候要和之前的 fiber 做下對比,決定怎么產生新的 fiber,對可復用的節點打上修改的標記,剩余的舊節點打上刪除標記,新節點打上新增標記。

接下來我們就來詳細了解下 React 的 diff 算法:

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 算法的核心。

責任編輯:姜華 來源: 神光的編程秘籍
相關推薦

2022-04-15 08:07:21

ReactDiff算法

2022-07-09 20:35:23

數字化企業轉型

2021-02-01 08:33:16

Redis排序內存

2024-12-05 09:45:25

Reactdiff 算法前端開發

2022-04-01 11:39:32

互聯網裁員紅利

2021-05-13 07:30:27

Kafka消息流系統

2023-07-03 07:51:47

2022-05-06 07:19:11

DOMDiff算法

2017-06-14 13:42:00

字典數據社交

2011-09-01 21:41:42

SQL Server把字符分割成兩個字符串

2020-10-26 08:19:53

算法隊列

2023-03-14 07:23:48

ReactJSX語法

2020-05-20 14:25:45

Reactreact.js前端

2022-06-28 15:13:12

Vuediff 算法

2023-12-06 07:16:31

Go語言語句

2021-08-03 08:13:47

數據

2022-01-05 09:40:03

DIff算法前端

2017-06-05 11:23:45

LinuxDiff和Meld工具

2010-03-04 09:50:14

企業定制軟件開發

2022-12-07 11:21:30

Reactdiff
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产成人在线视频播放 | 91精品国产91久久久久久吃药 | 久久精品国产一区二区电影 | 韩日一区二区 | 日韩一区在线播放 | 欧美偷偷 | 在线播放中文字幕 | 视频一区中文字幕 | 亚洲成人综合网站 | 一区二区三区免费 | 色久五月 | 国产成人在线播放 | 国产最好的av国产大片 | 久久久久久久久久久久91 | 日韩靠逼 | av一区二区三区在线观看 | 国产成人av电影 | 日韩中文在线视频 | 日韩中文字幕一区二区 | 最新一级毛片 | 久久久久无码国产精品一区 | 亚洲精品乱码久久久久久黑人 | 国产一级片精品 | 国产欧美精品一区二区三区 | 成人在线免费电影 | 中文欧美日韩 | 国产99精品 | 正在播放国产精品 | 欧美极品一区二区 | 日本一区不卡 | 久久99久久 | 亚洲网站在线观看 | 亚洲一区二区三区在线视频 | 一级全黄视频 | 欧美va大片| 久久久久久久久久久一区二区 | 天堂av中文 | 最新中文字幕一区 | 偷拍自拍第一页 | 天天狠狠 | 黄频视频|