欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

React超詳細(xì)講述Fiber的使用

 更新時(shí)間:2023年02月08日 08:52:58   作者:折桂懷橘  
在fiber出現(xiàn)之前,react的架構(gòu)體系只有協(xié)調(diào)器reconciler和渲染器render。當(dāng)前有新的update時(shí),react會(huì)遞歸所有的vdom節(jié)點(diǎn),如果dom節(jié)點(diǎn)過多,會(huì)導(dǎo)致其他事件影響滯后,造成卡頓。即之前的react版本無法中斷工作過程,一旦遞歸開始無法停留下來

Fiber

概念

JavaScript引擎和頁面渲染引擎兩個(gè)線程是互斥的,當(dāng)其中一個(gè)線程執(zhí)行時(shí),另一個(gè)線程只能掛起等待

如果 JavaScript 線程長時(shí)間地占用了主線程,那么渲染層面的更新就不得不長時(shí)間地等待,界面長時(shí)間不更新,會(huì)導(dǎo)致頁面響應(yīng)度變差,用戶可能會(huì)感覺到卡頓

破解JavaScript中同步操作時(shí)間過長的方法其實(shí)很簡單——分片。

把一個(gè)耗時(shí)長的任務(wù)分成很多小片,每一個(gè)小片的運(yùn)行時(shí)間很短,雖然總時(shí)間依然很長,但是在每個(gè)小片執(zhí)行完之后,都給其他任務(wù)一個(gè)執(zhí)行的機(jī)會(huì),這樣唯一的線程就不會(huì)被獨(dú)占,其他任務(wù)依然有運(yùn)行的機(jī)會(huì)。

React Fiber把更新過程碎片化,每執(zhí)行完一段更新過程,就把控制權(quán)交還給React負(fù)責(zé)任務(wù)協(xié)調(diào)的模塊,看看有沒有其他緊急任務(wù)要做,如果沒有就繼續(xù)去更新,如果有緊急任務(wù),那就去做緊急任務(wù)。

維護(hù)每一個(gè)分片的數(shù)據(jù)結(jié)構(gòu),就是Fiber。

一個(gè) Fiber 代表一個(gè)工作單元。

在react中,主要做了以下的操作:

  • 為每個(gè)增加了優(yōu)先級(jí),優(yōu)先級(jí)高的任務(wù)可以中斷低優(yōu)先級(jí)的任務(wù)。然后再重新,注意是重新執(zhí)行優(yōu)先級(jí)低的任務(wù)
  • 增加了異步任務(wù),調(diào)用requestIdleCallback api,瀏覽器空閑的時(shí)候執(zhí)行
  • dom diff樹變成了鏈表,一個(gè)dom對(duì)應(yīng)兩個(gè)fiber(一個(gè)鏈表),對(duì)應(yīng)兩個(gè)隊(duì)列,這都是為找到被中斷的任務(wù),重新執(zhí)行

從架構(gòu)角度來看,F(xiàn)iber 是對(duì) React核心算法(即調(diào)和過程)的重寫

從編碼角度來看,F(xiàn)iber是 React內(nèi)部所定義的一種數(shù)據(jù)結(jié)構(gòu),它是 Fiber樹結(jié)構(gòu)的節(jié)點(diǎn)單位,也就是 React 16 新架構(gòu)下的虛擬DOM

結(jié)構(gòu)

type Fiber = {
  // 用于標(biāo)記fiber的WorkTag類型,主要表示當(dāng)前fiber代表的組件類型如FunctionComponent、ClassComponent等
  tag: WorkTag,
  // ReactElement里面的key
  key: null | string,
  // ReactElement.type,調(diào)用`createElement`的第一個(gè)參數(shù)
  elementType: any,
  // The resolved function/class/ associated with this fiber.
  // 表示當(dāng)前代表的節(jié)點(diǎn)類型
  type: any,
  // 表示當(dāng)前FiberNode對(duì)應(yīng)的element組件實(shí)例
  stateNode: any,
  // 指向他在Fiber節(jié)點(diǎn)樹中的`parent`,用來在處理完這個(gè)節(jié)點(diǎn)之后向上返回
  return: Fiber | null,
  // 指向自己的第一個(gè)子節(jié)點(diǎn)
  child: Fiber | null,
  // 指向自己的兄弟結(jié)構(gòu),兄弟節(jié)點(diǎn)的return指向同一個(gè)父節(jié)點(diǎn)
  sibling: Fiber | null,
  index: number,
  ref: null | (((handle: mixed) => void) & { _stringRef: ?string }) | RefObject,
  // 當(dāng)前處理過程中的組件props對(duì)象
  pendingProps: any,
  // 上一次渲染完成之后的props
  memoizedProps: any,
  // 該Fiber對(duì)應(yīng)的組件產(chǎn)生的Update會(huì)存放在這個(gè)隊(duì)列里面
  updateQueue: UpdateQueue<any> | null,
  // 上一次渲染的時(shí)候的state
  memoizedState: any,
  // 一個(gè)列表,存放這個(gè)Fiber依賴的context
  firstContextDependency: ContextDependency<mixed> | null,
  mode: TypeOfMode,
  // Effect
  // 用來記錄Side Effect
  effectTag: SideEffectTag,
  // 單鏈表用來快速查找下一個(gè)side effect
  nextEffect: Fiber | null,
  // 子樹中第一個(gè)side effect
  firstEffect: Fiber | null,
  // 子樹中最后一個(gè)side effect
  lastEffect: Fiber | null,
  // 代表任務(wù)在未來的哪個(gè)時(shí)間點(diǎn)應(yīng)該被完成,之后版本改名為 lanes
  expirationTime: ExpirationTime,
  // 快速確定子樹中是否有不在等待的變化
  childExpirationTime: ExpirationTime,
  // fiber的版本池,即記錄fiber更新過程,便于恢復(fù)
  alternate: Fiber | null,
}

// 指向父級(jí)Fiber節(jié)點(diǎn)
this.return = null;
// 指向子Fiber節(jié)點(diǎn)
this.child = null;
// 指向右邊第一個(gè)兄弟Fiber節(jié)點(diǎn)
this.sibling = null;

Fiber樹的遍歷是這樣發(fā)生的深度遍歷

開始:Fiber 從最上面的 React 元素開始遍歷,并為其創(chuàng)建一個(gè) fiber 節(jié)點(diǎn)。

子節(jié)點(diǎn):然后,它轉(zhuǎn)到子元素,為這個(gè)元素創(chuàng)建一個(gè) fiber 節(jié)點(diǎn)。這樣繼續(xù)下去直到在沒有孩子

兄弟節(jié)點(diǎn): 現(xiàn)在,它檢查是否有兄弟節(jié)點(diǎn)元素。如果有,它就遍歷兄弟節(jié)點(diǎn)元素,然后再到兄弟姐妹的葉子元素。

返回:如果沒有兄弟節(jié)點(diǎn),那么它就返回到父節(jié)點(diǎn)。

window.requestIdleCallback()

該方法將在瀏覽器的空閑時(shí)段內(nèi)調(diào)用的函數(shù)排隊(duì)。方法提供 deadline,即任務(wù)執(zhí)行限制時(shí)間,以切分任務(wù),避免長時(shí)間執(zhí)行,阻塞UI渲染而導(dǎo)致掉幀;

【安排低優(yōu)先級(jí)或非必要的函數(shù)在幀結(jié)束時(shí)的空閑時(shí)間被調(diào)用】

requestAnimationFrame

安排高優(yōu)先級(jí)的函數(shù)在下一個(gè)動(dòng)畫幀之前被調(diào)用

Fiber是如何工作的

  • ReactDOM.render() 和 setState 的時(shí)候開始創(chuàng)建更新。
  • 將創(chuàng)建的更新加入任務(wù)隊(duì)列,等待調(diào)度。
  • 在 requestIdleCallback 空閑時(shí)執(zhí)行任務(wù)。
  • 從根節(jié)點(diǎn)開始遍歷 Fiber Node,并且構(gòu)建 WokeInProgress Tree。
  • 生成 effectList。
  • 根據(jù) EffectList 更新 DOM。

當(dāng)調(diào)用render和setState方法進(jìn)行組件渲染和更新的時(shí)候,react會(huì)經(jīng)歷倆個(gè)階段:reconciler和render階段:

  • 調(diào)和階段(Reconciler):官方解釋。React 會(huì)自頂向下通過遞歸,遍歷新數(shù)據(jù)生成新的 Virtual DOM,然后通過 Diff 算法,找到需要變更的元素(Patch),放到更新隊(duì)列里面去。
  • 渲染階段(Renderer):遍歷更新隊(duì)列,通過調(diào)用宿主環(huán)境的API,實(shí)際更新渲染對(duì)應(yīng)元素。宿主環(huán)境,比如 DOM、Native、WebGL 等。

React15 最大的問題就是,Reconciler(協(xié)調(diào))階段產(chǎn)生產(chǎn)生虛擬DOM是通過深度優(yōu)先遞歸的,并且中途不可間斷。所以假如虛擬DOM很深的話,由于 JS線程和瀏覽器 GUI 線程是互斥的,處理 js 的時(shí)間過長,會(huì)導(dǎo)致瀏覽器刷新的時(shí)候掉幀,造成卡頓。

而 React16則實(shí)現(xiàn)了異步的可中斷的更新。

Fiber 使用 requestAnimationFrame 來處理優(yōu)先級(jí)較高的更新,使用 requestIdleCallback 處理優(yōu)先級(jí)較低的更新。因此,在調(diào)度工作時(shí),F(xiàn)iber 檢查當(dāng)前更新的優(yōu)先級(jí)和 deadline (幀結(jié)束后的自由時(shí)間)。

如果優(yōu)先級(jí)高于待處理的工作,或者沒有 截止日期 或者截止日期尚未到達(dá),F(xiàn)iber 可以在一幀之后安排多個(gè)工作單元。而下一組工作單元會(huì)被帶到更多的幀上。這就是使 Fiber 有可能暫停、重用和中止工作單元的原因。

那么,讓我們看看在預(yù)定的工作中實(shí)際發(fā)生了什么。有兩個(gè)階段來完成工作。render 和 commit。

渲染階段

實(shí)際的樹形遍歷和 deadline 的使用發(fā)生在這個(gè)階段。這是 Fiber 的內(nèi)部邏輯,所以在這個(gè)階段對(duì) Fiber 樹所做的改變對(duì)用戶來說是不可見的。因此,F(xiàn)iber 可以暫停、中止或分擔(dān)多個(gè)框架的工作。

我們可以把這個(gè)階段稱為協(xié)調(diào)階段。 fiber 從 fiber 樹的根部開始遍歷,處理每個(gè) fiber 。每一個(gè)工作單位都會(huì)調(diào)用workLoop 函數(shù)來執(zhí)行工作。我們可以把這個(gè)工作的處理分成兩個(gè)步驟。begin 和 complete 。

開始階段

如果你從 React 代碼庫中找到 workLoop 函數(shù),它就會(huì)調(diào)用 performUnitOfWork,它把 nextUnitOfWork 作為一個(gè)參數(shù),它就只是個(gè)工作的單位,將被執(zhí)行。 performUnitOfWork 函數(shù)內(nèi)部調(diào)用 beginWork 函數(shù)。這是 fiber 上發(fā)生實(shí)際工作的地方,而 performUnitOfWork 只是發(fā)生迭代的地方。

在 beginWork 函數(shù)中,如果 fiber 沒有任何待處理的工作,它就會(huì)直接跳出(跳過) fiber 而不進(jìn)入開始階段。這就是在遍歷大樹時(shí), fiber 跳過已經(jīng)處理過的 fiber ,直接跳到有待處理工作的 fiber 。如果你看到大的 beginWork 函數(shù)代碼塊,我們會(huì)發(fā)現(xiàn)一個(gè)開關(guān)塊,根據(jù) fiber 標(biāo)簽,調(diào)用相應(yīng)的 fiber 更新函數(shù)。就像 updateHostComponent 用于宿主組件。這些函數(shù)會(huì)更新 fiber 。

如果有子 fiber ,beginWork函數(shù)返回子 fiber ,如果沒有子 fiber 則返回空。函數(shù) performUnitOfWork 持續(xù)迭代并調(diào)用子 fiber ,直到葉節(jié)點(diǎn)到達(dá)。在葉子節(jié)點(diǎn)的情況下,beginWork 返回 null,因?yàn)闆]有任何子節(jié)點(diǎn),performUnitOfWork 函數(shù)調(diào)用 completeUnitOfWork 函數(shù)?,F(xiàn)在讓我們看看完善階段。

完善階段

這個(gè) completeUnitOfWork 函數(shù)通過調(diào)用一個(gè) completeWork 函數(shù)來完成當(dāng)前單位的工作。如果有的話,completeUnitOfWork 會(huì)返回一個(gè)同級(jí)的 fiber 來執(zhí)行下一個(gè)工作單元,如果沒有工作的話,則會(huì)完成 return(parent) fiber 。這將一直持續(xù)到返回值為空,也就是說,直到它到達(dá)根節(jié)點(diǎn)。和 beginWork 一樣,completeWork 也是一個(gè)發(fā)生實(shí)際工作的函數(shù),而 completeUnitOfWork 是用于迭代的。

渲染階段的結(jié)果會(huì)產(chǎn)生一個(gè)效果列表(副作用)。這些效果就像插入、更新或刪除宿主組件的節(jié)點(diǎn),或調(diào)用類組件節(jié)點(diǎn)的生命周期方法。這些 fiber 被標(biāo)記為各自的效果標(biāo)簽。

在渲染階段之后,F(xiàn)iber 將準(zhǔn)備提交更新。

提交階段

這是一個(gè)階段,完成的工作將被用來在用戶界面上渲染它。由于這一階段的結(jié)果對(duì)用戶來說是可見的,所以不能被分成部分渲染。這個(gè)階段是一個(gè)同步的階段。

在這個(gè)階段的開始,F(xiàn)iber 有已經(jīng)在 UI 上渲染的 current 樹,finishedWork,或者在渲染階段建立的 workInProgress 樹和效果列表。

effect 列表是 fiber 的鏈表,它有副作用。所以,它是渲染階段的 workInProgress 樹的節(jié)點(diǎn)的一個(gè)子集,它有副作用(更新)。effect 列表的節(jié)點(diǎn)是用 nextEffect 指針鏈接的。

在這個(gè)階段調(diào)用的函數(shù)是 completeRoot。

在這里,workInProgress 樹成為 current 樹,因?yàn)樗挥脕礓秩?UI。實(shí)際的 DOM 更新,如插入、更新、刪除,以及對(duì)生命周期方法的調(diào)用或者更新相對(duì)應(yīng)的引用 —— 發(fā)生在 effect 列表中的節(jié)點(diǎn)上。

這就是 fiber 協(xié)調(diào)器的工作方式。

結(jié)論

這就是 React Fiber 協(xié)調(diào)器使之有可能將工作分為多個(gè)工作單元。它設(shè)置每個(gè)工作的優(yōu)先級(jí),并使暫停、重用和中止工作單元成為可能。在 fiber 樹中,單個(gè)節(jié)點(diǎn)保持跟蹤,這是使上述事情成為可能的需要。每個(gè) fiber 都是一個(gè)鏈表的節(jié)點(diǎn),它們通過子、兄弟節(jié)點(diǎn)和返回引用連接起來。

  • 有react fiber,為什么不需要vue fiber “我們現(xiàn)在已經(jīng)知道了react fiber是在彌補(bǔ)更新時(shí)“無腦”刷新,不夠精確帶來的缺陷。”fiber不是用來彌補(bǔ)無腦刷新的,fibe是用來讓原來同步的調(diào)用顆?;?,解決無腦刷新你應(yīng)該用meno
  • vue不需要fiber是因?yàn)樗褂胣extTick來異步?jīng)Q定什么時(shí)候執(zhí)行renderfunction 本質(zhì)上思路是和react一致的和響應(yīng)式原理沒有半毛錢關(guān)系

到此這篇關(guān)于React超詳細(xì)講述Fiber的使用的文章就介紹到這了,更多相關(guān)React Fiber內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React中的Hooks路由跳轉(zhuǎn)問題

    React中的Hooks路由跳轉(zhuǎn)問題

    這篇文章主要介紹了React中的Hooks路由跳轉(zhuǎn)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 在React項(xiàng)目中添加吸頂效果的代碼示例

    在React項(xiàng)目中添加吸頂效果的代碼示例

    在大型Web應(yīng)用中,一個(gè)常見的設(shè)計(jì)需求是讓某些組件具有吸頂效果,這意味著當(dāng)頁面向下滾動(dòng)時(shí),該組件會(huì)保持在屏幕頂部,在本文中,我們將介紹如何在React項(xiàng)目中實(shí)現(xiàn)吸頂效果。我們將首先討論使用原生JavaScript領(lǐng)域的方法來實(shí)現(xiàn),然后將這些方法與React結(jié)合起來
    2023-06-06
  • React學(xué)習(xí)筆記之高階組件應(yīng)用

    React學(xué)習(xí)筆記之高階組件應(yīng)用

    這篇文章主要介紹了React 高階組件應(yīng)用,詳細(xì)的介紹了什么是React高階組件和具體使用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-06-06
  • react實(shí)現(xiàn)移動(dòng)端二級(jí)路由嵌套詳解

    react實(shí)現(xiàn)移動(dòng)端二級(jí)路由嵌套詳解

    這篇文章主要介紹了react移動(dòng)端二級(jí)路由嵌套的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • React useImperativeHandle處理組件狀態(tài)和生命周期用法詳解

    React useImperativeHandle處理組件狀態(tài)和生命周期用法詳解

    React Hooks 為我們提供了一種全新的方式來處理組件的狀態(tài)和生命周期,useImperativeHandle是一個(gè)相對(duì)較少被提及的Hook,但在某些場景下,它是非常有用的,本文將深討useImperativeHandle的用法,并通過實(shí)例來加深理解
    2023-09-09
  • 使用Node搭建reactSSR服務(wù)端渲染架構(gòu)

    使用Node搭建reactSSR服務(wù)端渲染架構(gòu)

    這篇文章主要介紹了使用Node搭建reactSSR服務(wù)端渲染架構(gòu),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • 每天一個(gè)hooks學(xué)習(xí)之useUnmount

    每天一個(gè)hooks學(xué)習(xí)之useUnmount

    這篇文章主要為大家介紹了每天一個(gè)hooks學(xué)習(xí)之useUnmount,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • React useCallback鉤子的作用方法demo

    React useCallback鉤子的作用方法demo

    這篇文章主要為大家介紹了React useCallback鉤子的作用方法demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • React編程中需要注意的兩個(gè)錯(cuò)誤

    React編程中需要注意的兩個(gè)錯(cuò)誤

    React可以說是前端的先驅(qū)者,它總是會(huì)引領(lǐng)整個(gè)前端的潮流。 但我們在使用也經(jīng)常會(huì)遇到錯(cuò)誤,下面這篇文章主要給大家介紹了關(guān)于React編程中需要注意的兩個(gè)錯(cuò)誤,需要的朋友可以參考下
    2021-05-05
  • 詳解React native全局變量的使用(跨組件的通信)

    詳解React native全局變量的使用(跨組件的通信)

    本篇文章主要介紹了詳解React native全局變量的使用(跨組件的通信),具有一定的參考價(jià)值,有興趣的同學(xué)可以了解一下
    2017-09-09

最新評(píng)論