一文講清楚React Fiber

文章目錄

  • 一文講清楚React Fiber
  • 1. 基礎概念
    • 1.1瀏覽器刷新率(幀)
    • 1.2 JS執行棧
    • 1.3 時間分片
    • 1.4 鏈表
  • 2. React Fiber是如何實現更新過程控制
    • 2.1 任務拆分
    • 2.2掛起、恢復、終止
      • 2.2.1 掛起
      • 2.2.2 恢復
      • 2.2.3 終止
    • 2.3 任務具備優先級

一文講清楚React Fiber

1. 基礎概念

1.1瀏覽器刷新率(幀)

  • 頁面都是一幀一幀繪制出來的,瀏覽器大多是60Hz(60幀/s),每一幀耗時16ms左右,每一幀分為以下7個過程
    1. 接手輸入事件
    1. 執行回調事件
    1. 開始一幀
    1. 執行RequestAnimationFrame,即RAF
    1. 頁面布局,計算樣式
    1. 渲染
    1. 執行RequestIdleCallback,即RIC
  • 其中,RIC事件并不是每一幀結束都會執行,只有在一幀的16ms內做完了前6件事切還有剩余時間,RIC才會執行。如果執行了RIC事件,那么下一幀就要在事件執行結束后才能繼續渲染,所以RIC的執行時間不宜太長,不然瀏覽器得不到控制權,無法完成下一幀的渲染,會出現頁面卡頓

1.2 JS執行棧

  • React16之前,是通過原生執行棧遞歸遍歷DOM,會形成一個執行棧,每次更新瀏覽器會從棧頂開始執行,直到執行棧被清空才會把執行權交給瀏覽器。而在React中,頁面視圖都被視為一個個函數執行的結果,這就意味著有多個函數的調用。如果頁面很復雜,執行棧就會很深,就要占據很長的一段時間,瀏覽器渲染就會停滯,就會出現卡頓等問題

1.3 時間分片

  • 就是將粒度很小的任務放入一個時間段(一幀)去執行的一種方案,React Fiber就是將多個任務放入一個時間分片去執行

1.4 鏈表

  • 鏈表的概念不用多少說
  • React16之后,使用多向鏈表代替了原來的樹結構,同時還會生成副作用單鏈表和狀態更新單鏈表

2. React Fiber是如何實現更新過程控制

  • 過程可控體現在三方面
    1. 任務拆分
    1. 任務掛起、恢復、終止
    1. 任務具備優先級

2.1 任務拆分

  • React Fiber 將遍歷VDOM拆分成若干個小任務,每個人物只負責一個節點的處理

2.2掛起、恢復、終止

  • 在React Fiber架構中,更新過程的核心在于兩棵Fiber樹的協同工作:當前工作樹(workInProgress)和當前渲染樹(current)。這兩棵樹構成了React實現可中斷渲染的基礎架構。

  • 工作樹(workInProgress)是React在執行更新時正在構建的新版本Fiber樹。每當應用狀態發生變化(如通過setState觸發更新),React就會開始構建這棵新樹。在構建過程中,每個Fiber節點都- 會記錄自身的變更標記(effectTag),最終整棵樹會形成完整的變更鏈表。

  • 當前樹(current)則代表著上次渲染周期最終呈現的UI對應的Fiber結構。每次更新完成后,新構建的workInProgress樹就會成為新的current樹。在下一次更新開始時,React會基于這個current樹- 創建新的workInProgress樹,并通過alternate指針在兩樹的對應節點間建立關聯。

  • 在構建新workInProgress樹的過程中,React會執行關鍵的協調算法:

  • 通過對比新舊節點(diff算法)來確定需要應用的變更

  • 盡可能復用current樹中的節點實例,避免不必要的對象創建

  • 為每個節點標記具體的更新類型(如新增、修改或刪除)

  • 整個更新過程本質上就是workInProgress樹的漸進式構建過程:

  • React會將構建任務分解為多個工作單元

  • 每個工作單元完成后可以暫停讓出主線程

  • 通過循環調度機制繼續處理下一個工作單元

  • 這種分片執行方式使得高優先級更新可以中斷低優先級任務

  • 這種雙樹機制賦予了React三大核心能力:

  • 可中斷的漸進式渲染

  • 更新優先級的智能調度

  • 高效的節點復用策略

  • 值得注意的是,所有與任務調度相關的操作(暫停、恢復或取消)都發生在workInProgress樹的構建階段。React通過這種巧妙的架構設計,在保持聲明式編程模型的同時,實現了接近原生渲染的性能表現。

2.2.1 掛起

  • 當第一個小任務完成后,先判斷這一幀是否還有空閑時間,沒有就掛起下一個任務的執行,記住當前掛起的節點,讓出控制權給瀏覽器執行更高優先級的任務。

2.2.2 恢復

  • 在瀏覽器渲染完一幀后,判斷當前幀是否有剩余時間,如果有就恢復執行之前掛起的任務。如果沒有任務需要處理,代表調和階段完成,可以開始進入渲染階段。這樣完美的解決了調和過程一直占用主線程的問題。
    那么問題來了他是如何判斷一幀是否有空閑時間的呢?答案就是我們前面提到的 RIC (RequestIdleCallback) 瀏覽器原生 API,React 源碼中為了兼容低版本的瀏覽器,對該方法進行了 Polyfill。

當恢復執行的時候又是如何知道下一個任務是什么呢?答案在前面提到的鏈表。在 React Fiber 中每個任務其實就是在處理一個 FiberNode 對象,然后又生成下一個任務需要處理的 FiberNode

class FiberNode {constructor(tag, pendingProps, key, mode) {// 實例屬性this.tag = tag; // 標記不同組件類型,如函數組件、類組件、文本、原生組件...this.key = key; // react 元素上的 key 就是 jsx 上寫的那個 key ,也就是最終 ReactElement 上的this.elementType = null; // createElement的第一個參數,ReactElement 上的 typethis.type = null; // 表示fiber的真實類型 ,elementType 基本一樣,在使用了懶加載之類的功能時可能會不一樣this.stateNode = null; // 實例對象,比如 class 組件 new 完后就掛載在這個屬性上面,如果是RootFiber,那么它上面掛的是 FiberRoot,如果是原生節點就是 dom 對象// fiberthis.return = null; // 父節點,指向上一個 fiberthis.child = null; // 子節點,指向自身下面的第一個 fiberthis.sibling = null; // 兄弟組件, 指向一個兄弟節點this.index = 0; //  一般如果沒有兄弟節點的話是0 當某個父節點下的子節點是數組類型的時候會給每個子節點一個 index,index 和 key 要一起做 diffthis.ref = null; // reactElement 上的 ref 屬性this.pendingProps = pendingProps; // 新的 propsthis.memoizedProps = null; // 舊的 propsthis.updateQueue = null; // fiber 上的更新隊列執行一次 setState 就會往這個屬性上掛一個新的更新, 每條更新最終會形成一個鏈表結構,最后做批量更新this.memoizedState = null; // 對應  memoizedProps,上次渲染的 state,相當于當前的 state,理解成 prev 和 next 的關系this.mode = mode; // 表示當前組件下的子組件的渲染方式// effectsthis.effectTag = NoEffect; // 表示當前 fiber 要進行何種更新this.nextEffect = null; // 指向下個需要更新的fiberthis.firstEffect = null; // 指向所有子節點里,需要更新的 fiber 里的第一個this.lastEffect = null; // 指向所有子節點中需要更新的 fiber 的最后一個this.expirationTime = NoWork; // 過期時間,代表任務在未來的哪個時間點應該被完成this.childExpirationTime = NoWork; // child 過期時間this.alternate = null; // current 樹和 workInprogress 樹之間的相互引用}
}

2.2.3 終止

  • 其實并不是每次更新都會走到提交階段。當在調和過程中觸發了新的更新,在執行下一個任務的時候,判斷是否有優先級更高的執行任務,如果有就終止原來將要執行的任務,開始新的 workInProgressFiber 樹構建過程,開始新的更新流程。這樣可以避免重復更新操作。這也是在 React 16 以后生命周期函數 componentWillMount 有可能會執行多次的原因

2.3 任務具備優先級

  • React Fiber 除了通過掛起,恢復和終止來控制更新外,還給每個任務分配了優先級。具體點就是在創建或者更新 FiberNode 的時候,通過算法給每個任務分配一個到期時間(expirationTime)。在每個任務執行的時候除了判斷剩余時間,如果當前處理節點已經過期,那么無論現在是否有空閑時間都必須執行改任務
  • 同時過期時間的大小還代表著任務的優先級。
    任務在執行過程中順便收集了每個 FiberNode 的副作用,將有副作用的節點通過 firstEffect、lastEffect、nextEffect 形成一條副作用單鏈表

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/913521.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/913521.shtml
英文地址,請注明出處:http://en.pswp.cn/news/913521.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

(3)機器學習小白入門 YOLOv: 解鎖圖片分類新技能

(1)機器學習小白入門YOLOv :從概念到實踐 (2)機器學習小白入門 YOLOv:從模塊優化到工程部署 (3)機器學習小白入門 YOLOv: 解鎖圖片分類新技能 前言 YOLOv 算法通常被用于目標檢測任務,但通過對其進行適當的調整和改造&#xff0c…

主機安全-開源HIDS字節跳動Elkeid使用

安裝好elkeid后就開始接入主機和k8s集群,安裝文檔-----主機安全-開源HIDS字節跳動Elkeid安裝-CSDN博客 1、接入主機 在系統管理-----安裝配置-----復制命令------在目標機器上執行這段命令 執行成功后主機就會自動接入 2、接入k8s集群 在k8s主機上執行腳本&#x…

【vue】用conda配置nodejs,一鍵開通模版使用權

特此鳴謝我的好同學重中之重的特級教學,非常之好用一、conda環境下載安裝二、創建包含nodejs的conda環境創建一個新環境:conda create -n 【自定義環境名字】 python3.9 conda create -n my_nodejs_env python3.9激活新環境:conda activate【…

深度學習--tensor(創建、屬性)

一、torch概念1.1簡介pytorch簡稱torch,意為深度學習框架。它使用張量(tensor)來表示數據,可以輕松地處理大規模數據集,且可以在GPU上加速。pytorch基本功能:自動微分、自動求導等。1.2安裝官網獲得下載命令…

【內存】Linux 內核優化實戰 - net.ipv4.tcp_max_tw_buckets

目錄net.ipv4.tcp_max_tw_buckets 詳解一、基本概念二、核心作用三、默認值四、調整場景需增大參數的場景需減小參數的場景五、查看與修改方法1. 查看當前值2. 臨時修改(重啟失效)3. 永久修改(重啟生效)六、注意事項總結net.ipv4.…

短劇系統開發定制全流程解析:從需求分析到上線運營

一、短劇行業現狀與系統開發價值短劇作為一種新興的內容形態,近年來呈現爆發式增長態勢。2023年中國短劇市場規模已突破300億元,用戶規模超過5億,這種以"快節奏、強劇情、低成本"為特點的內容形式正在重塑數字娛樂產業格局。短劇系…

各服務器廠商調整BIOS睿頻教程

調整BIOS睿頻選項匯總:1、華為服務器:2、華為服務器V53、浪潮服務器4、浪潮服務器M45、 曙光服務器5.1 曙光I620-G205.2 曙光I620-G306、聯想服務器(650系列)650系列的服務器對照截圖信息修改對應項,修改為截圖里的選項…

PyTorch筆記3----------統計學相關函數

1.基礎函數 import torch a torch.rand(2,2) print("a:\n",a) print(########################) print("平均值:\n",torch.mean(a,dim0)) print("總和:\n",torch.sum(a,dim0)) print("所有元素的積:\n",torch.prod(a,dim0)) print(&…

【Prometheus】通過tar包部署單機版Prometheus 和 Pushgateway

在ECS(Elastic Compute Service)機器上通過tar包部署 Prometheus 和 Pushgateway,并配置 Prometheus 采集 Pushgateway 的數據,是一個常見的監控部署任務。以下是詳細的步驟說明:🧩 環境準備 操作系統&…

Matlab 頻譜分析 (Spectral Analysis)

文章目錄1. 信號預處理 - 去直流分量2. 快速傅里葉變換(FFT)3. 功率譜密度(PSD)計算4. 主頻率檢測5. 譜質心計算6. 對數譜顯示完整的信號處理流程實際應用示例1. 信號預處理 - 去直流分量 data data - mean(data);數學原理&…

【實時Linux實戰系列】實時以太網與 TSN 基礎

在實時系統中,網絡通信的實時性和可靠性是確保系統正常運行的關鍵。實時以太網和時間敏感網絡(TSN)技術為實時數據傳輸提供了強大的支持。TSN通過一系列協議和機制,確保數據能夠在預定的時間內可靠傳輸,滿足工業自動化…

茶顏悅色JAVA面試分享

1、自我介紹項目2、設計一個爆款飲品秒殺系統:如何解決“幽蘭拿鐵”上新時的瞬時10萬QPS?從緩存、限流、庫存扣減到訂單創建的全流程設計。3、訂單超市未支付自動取消:如何實現高精度(30分鐘精確到秒)且低延遲的訂單狀…

OneCode圖表配置速查手冊

前言 在數據可視化日益成為業務決策核心驅動力的今天,高效、靈活的圖表配置系統已成為開發人員不可或缺的工具。OneCode圖表組件憑借其豐富的圖表類型與精細化的配置能力,為開發者提供了構建專業數據可視化界面的完整解決方案。然而,隨著圖表…

二維碼驅動的獨立站視頻集成方案

一、獨立站視頻嵌入的技術挑戰與架構設計 在獨立站建設中,視頻內容的集成面臨著性能、安全與用戶體驗的三重挑戰。傳統直接嵌入方式會導致頁面加載緩慢(平均增加3-5秒首屏時間)、服務器帶寬消耗激增(單視頻日均播放1000次約產生50…

【STM32】預分頻因子(Prescaler)和重裝載值(Reload Value)

在 STM32 的 獨立看門狗(IWDG) 中(結合上文【STM32】獨立看門狗(提供完整實例代碼)),為了控制看門狗的超時時間(溢出時間),我們主要設置兩個參數:…

從0到1搭建同城O2O外賣平臺:外賣系統源碼架構解析與實戰指南

當下,越來越多的創業者、品牌連鎖商家,甚至社區集群,開始布局屬于自己的本地外賣平臺。而對于軟件開發者和技術團隊而言,如何從0到1搭建一套可落地、可擴展、可持續運營的外賣系統,成為了一個既現實又挑戰性十足的話題…

MySQL 8.0 OCP 1Z0-908 題目解析(16)

題目61 Choose the best answer. Examine this command, which executes successfully: mysqlbackup --defaults-file/backups/server-my.cnf --backup-dir/backups/full copy-backWhich statement is true about the copy-back process? ○ A) It restores files from the da…

WSL命令

以下是 WSL&#xff08;Windows Subsystem for Linux&#xff09;的常用命令大全&#xff0c;涵蓋安裝、管理、網絡、文件交互等場景&#xff0c;方便快速查閱和使用&#xff1a;1. 安裝與版本管理命令說明wsl --install默認安裝 WSL 和 Ubuntuwsl --install -d <發行版名&g…

AI語音訓練——GPT-SoVITS(GSV)

鏈接說明 github項目地址&#xff1a;RVC-Boss/GPT-SoVITS: 1 min voice data can also be used to train a good TTS model! (few shot voice cloning) 項目中文說明書&#xff1a; GPT-SoVITS指南//項目說明書里也有在線使用的鏈接 原項目作者B站教學視頻&#xff1a;耗時兩個…

事件委托版本tab欄切換

事件委托&#xff1a;是JavaScript中注冊事件的常用技巧&#xff0c;也稱事件委派、事件代理簡單理解&#xff1a;原本需要注冊在子元素的事件委托給父元素&#xff0c;讓父元素擔當事件監聽的職務優點&#xff1a;減少注冊次數&#xff0c;可提高程序性能原理&#xff1a;事件…