自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一篇帶你了解 React Fiber 是什么?

開發(fā) 前端
Fiber,本意為 “纖維”,在計(jì)算機(jī)世界中則是 ”纖程“ 的意思。纖程可以看作是協(xié)程的一種,是一種 任務(wù)調(diào)度 方式。

大家好,我是前端西瓜哥。

為了提高 React 的性能,React 團(tuán)隊(duì)在開發(fā) React 16 時(shí)做了底層的重構(gòu),引入了 React Fiber 的概念。

React Fiber 是什么?

Fiber,本意為 “纖維”,在計(jì)算機(jī)世界中則是 ”纖程“ 的意思。纖程可以看作是協(xié)程的一種,是一種任務(wù)調(diào)度方式。

JavaScript 是單線程的,有一個(gè) event loop 的概念,它有一個(gè)有優(yōu)先級的任務(wù)隊(duì)列,只能按順序執(zhí)行一個(gè)任務(wù),是不支持多個(gè)任務(wù)同時(shí)執(zhí)行的。

這種設(shè)計(jì)的好處就是不用考慮多線程導(dǎo)致的順序問題,并為此做一些加鎖的額外邏輯,確保執(zhí)行順序符合預(yù)期。但也因?yàn)闊o法使用并行能力,在 CPU 密集的場景會有性能問題, 比如一個(gè)任務(wù)耗時(shí)過長會導(dǎo)致其他的任務(wù),導(dǎo)致用戶的交互響應(yīng)發(fā)生延遲。

?React 的組件更新是 CPU 密集的操作,因?yàn)樗鰧Ρ刃屡f虛擬 DOM 樹的操作(diff,React 中 Reconcilation 負(fù)責(zé)),找出需要更新的內(nèi)容(patch),通過打補(bǔ)丁的方式更新真實(shí) DOM 樹(React 中 Renderer 負(fù)責(zé))。當(dāng)要對比的組件樹非常多時(shí),就會發(fā)生大量的新舊節(jié)點(diǎn)對比,CPU 花費(fèi)時(shí)間龐大,當(dāng)耗時(shí)大大超過 16.6ms(一秒 60 幀的基準(zhǔn)) 時(shí),用戶會感覺到明顯的卡頓。

這一系列操作是通過遞歸的方式實(shí)現(xiàn)的,是 同步且不可中斷 的。因?yàn)橐坏┲袛?,調(diào)用棧就會被銷毀,中間的狀態(tài)就丟失了。這種基于調(diào)用棧的實(shí)現(xiàn),我們稱為 Stack Reconcilation。

React 16 的一個(gè)重點(diǎn)工作就是優(yōu)化更新組件時(shí)大量的 CPU 計(jì)算,最后選擇了使用 “時(shí)間分片” 的方案,就是將原本要一次性做的工作,拆分成一個(gè)個(gè)異步任務(wù),在瀏覽器空閑的時(shí)間時(shí)執(zhí)行。這種新的架構(gòu)稱為 Fiber Reconcilation。

在 React 中,F(xiàn)iber 模擬之前的遞歸調(diào)用,具體通過鏈表的方式去模擬函數(shù)的調(diào)用棧,這樣就可以做到中斷調(diào)用,將一個(gè)大的更新任務(wù),拆分成小的任務(wù),并設(shè)置優(yōu)先級,在瀏覽器空閑的時(shí)異步執(zhí)行。

FiberNode

前面我們說到使用了鏈表的遍歷來模擬遞歸棧調(diào)用,其中鏈表的節(jié)點(diǎn) React 用 FiberNode 表示。

FiberNode 其實(shí)就是虛擬 DOM,它記錄了:

  1. 節(jié)點(diǎn)相關(guān)類型,比如 tag 表示組件類型、type 表示元素類型等。
  2. 節(jié)點(diǎn)的指向。
  3. 副作用相關(guān)的屬性。
  4. lanes 是關(guān)于調(diào)度優(yōu)先級的。
function FiberNode(
tag: WorkTag,
pendingProps: mixed,
key: null | string,
mode: TypeOfMode,
) {
// Instance
this.tag = tag; // 組件類型,比如 Function/Class/Host
this.key = key; // key 唯一值,通常會在列表中使用
this.elementType = null;
this.type = null; // 元素類型,字符串或類或函數(shù),比如 "div"/ComponentFn/Class
this.stateNode = null; // 指向真實(shí) DOM 對象
// Fiber
this.return = null; // 父 Fiber
this.child = null; // 子 Fiber 的第一個(gè)
this.sibling = null; // 下一個(gè)兄弟節(jié)點(diǎn)
this.index = 0; // 在同級兄弟節(jié)點(diǎn)中的位置
this.ref = null;
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
// Effects
this.flags = NoFlags;
this.subtreeFlags = NoFlags;
this.deletions = null;
this.lanes = NoLanes;
this.childLanes = NoLanes;
this.alternate = null;
// ...
}

Fiber 通過 return 指向父 Fiber,child 指向子 Fiber 的首位、sibling 指向下一個(gè)兄弟節(jié)點(diǎn)。通過它們我們其實(shí)就能拿到一個(gè)完整的結(jié)構(gòu)樹。

對于:

function App() {
return (
<div className="app">
<span>hello</span>, Fiber
</div>
);
}

形成的 Fiber 樹為:

圖片

其中弧線為調(diào)用順序。紫色為 beginWork、粉色為 completeWork。beginWork 是 “遞” 的過程,而 comleteWork 則是 “歸” 的過程。

為什么不用 generator 或 async/await?

generator 和 async/await 也可以做到在函數(shù)中間暫停函數(shù)執(zhí)行的邏輯,將執(zhí)行讓出去,能做到將同步變成異步。

但 React 沒有選擇它們,這是因?yàn)椋?/p>

  1. 具有傳染性,比如一個(gè)函數(shù)用了 async,調(diào)用它的函數(shù)就要加上 async,有語法開銷,此外也會有性能上的額外開銷。
  2. 無法在 generator 和 async/await 中恢復(fù)一些中間狀態(tài)。

具體見官方的 github issue 討論:

https://github.com/facebook/react/issues/7942#issuecomment-254987818。

Scheduler

圖片

做了時(shí)間分片,拆分了多個(gè)任務(wù),React 就可以以此為基石,給任務(wù)設(shè)置優(yōu)先級。

React 實(shí)現(xiàn)了一個(gè) Scheduler(調(diào)度器)來實(shí)現(xiàn)任務(wù)調(diào)度執(zhí)行,并單獨(dú)抽離為一個(gè)單獨(dú)的包,它會在瀏覽器有空閑的時(shí)候執(zhí)行。其實(shí)瀏覽器也提供了一個(gè) requestIdleCallback 的 API,支持這個(gè)能力,但兼容性實(shí)在不好,React 還是自己實(shí)現(xiàn)了一套。

這個(gè) Scheduler 支持優(yōu)先級,底層使用了 小頂堆,確保能高效拿到最快要過期的任務(wù),然后執(zhí)行它。

小頂堆,其實(shí)就是優(yōu)先級隊(duì)列。小頂堆在結(jié)構(gòu)上是一個(gè)完全二叉樹,但能保證每次從堆頂取出元素時(shí),是最小的元素。

任務(wù)的 優(yōu)先級 分為幾種:

  1. NoPriority:無優(yōu)先級。
  2. ImmediatePriority:立即執(zhí)行。
  3. UserBlockingPriority:用戶阻塞優(yōu)先級,不執(zhí)行可能會導(dǎo)致用戶交互阻塞。
  4. NormalPriority:普通優(yōu)先級。
  5. LowPriority:低優(yōu)先級。
  6. IdlePriority:空閑優(yōu)先級。

React 自身也有優(yōu)先級,叫做 Lane,兩者是不同的。

結(jié)尾

React 的架構(gòu)過于宏大,今天先隨便說一點(diǎn)吧。

總的來說,React Fiber 是在 React 16 中引入的新的架構(gòu),將原本同步不可中斷的更新,變成異步可中斷更新,將原本一個(gè)耗時(shí)的大任務(wù)做了時(shí)間分片,拆分成一個(gè)個(gè)小任務(wù),在瀏覽器空閑的時(shí)間執(zhí)行。此外添加優(yōu)先級的概念,將一些重要的任務(wù)先執(zhí)行,比如一些用戶交互的響應(yīng)函數(shù)。

一切為了更好的用戶體驗(yàn)。

責(zé)任編輯:姜華 來源: 前端西瓜哥
相關(guān)推薦

2021-05-20 06:57:16

RabbitMQ開源消息

2022-03-23 08:31:25

LRU 算法JavaScripLFU 緩存算法

2023-05-12 08:19:12

Netty程序框架

2021-06-30 00:20:12

Hangfire.NET平臺

2021-07-28 10:02:54

建造者模式代碼

2021-07-14 08:24:23

TCPIP 通信協(xié)議

2021-08-11 07:02:21

npm包管理器工具

2021-08-02 06:34:55

Redis刪除策略開源

2021-11-08 08:42:44

CentOS Supervisor運(yùn)維

2021-11-24 08:51:32

Node.js監(jiān)聽函數(shù)

2021-12-15 11:52:34

GPLLinuxGNU

2021-07-07 07:14:48

分布式ID分布式系統(tǒng)

2022-12-20 08:22:42

CommitMuation

2020-11-10 10:48:10

JavaScript屬性對象

2021-01-29 18:41:16

JavaScript函數(shù)語法

2021-02-02 18:39:05

JavaScript

2021-06-04 09:56:01

JavaScript 前端switch

2021-08-14 10:01:43

Python條件語句Python基礎(chǔ)

2021-07-08 06:30:03

Linux CPULinux 系統(tǒng)

2022-02-23 09:36:11

GoRuby編程語言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號