React 原理篇 - React 新架構深度解析

使用過 React v16 之前版本的開發者或許都經歷過這樣的場景:當頁面包含復雜組件或大量列表時,輸入框打字會卡頓,滾動會不流暢。這些體驗問題的背后,往往與 React 的渲染機制密切相關。2017 年 React v16 推出的 Fiber 架構,正是為解決這些核心問題而生。本文將系統解讀 React 新架構的演進之路。

一、舊架構的性能瓶頸:為什么會卡頓?

在 Fiber 出現之前,React 使用的是基于棧的遞歸協調(Stack Reconciler)機制。這種架構在處理復雜組件樹時,會暴露出難以克服的性能問題。

1.1 不可中斷的同步更新

JavaScript 是單線程語言,瀏覽器的渲染(UI 繪制)和腳本執行共用一個主線程。Stack Reconciler 采用深度優先遞歸方式比對虛擬 DOM,這種方式有一個致命缺陷:一旦開始執行,就必須等到整個組件樹處理完成才能釋放主線程。

想象一個包含 1000 個項目的列表:React 會從根組件開始,逐層遞歸處理每個子組件,整個過程無法暫停。如果這個過程耗時超過 16ms(瀏覽器每秒刷新 60 幀的時間間隔),就會阻塞渲染,導致頁面卡頓。用戶輸入、鼠標移動等交互事件也會因為主線程被占用而無法及時響應。

1.2 缺乏優先級區分

舊架構對所有更新一視同仁,無法區分任務的輕重緩急。例如:

  • 用戶正在輸入搜索關鍵詞(高優先級,需要即時反饋)
  • 同時頁面在后臺加載并渲染搜索結果(低優先級)

在 Stack 架構中,這兩個任務會搶占主線程,可能導致輸入框響應延遲,嚴重影響用戶體驗。

1.3 遞歸調用棧的限制

遞歸調用會形成一個連續的調用棧,棧的深度與組件樹的深度一致。當組件樹層級較深時,不僅容易導致棧溢出錯誤,更重要的是:JavaScript 引擎無法在遞歸過程中暫停執行某部分任務。這種機制使得 React 無法靈活應對運行時的各種情況,比如中途插入高優先級任務。

二、Fiber 架構:如何解決這些問題?

Fiber 架構的設計初衷,就是要打破 Stack Reconciler 的限制,實現 “可控的渲染過程”。它不是簡單的優化,而是一次底層架構的重構。

2.1 核心目標:實現可中斷、可恢復的更新

Fiber 架構通過兩大革新實現這一目標:

  • 把渲染任務分解為小單元(每個單元對應一個組件的處理)
  • 每個單元執行完成后,允許暫停、恢復甚至放棄執行

這樣,React 可以在處理完一個小單元后檢查:是否有更高優先級的任務需要處理?當前是否已經超過了瀏覽器的一幀時間?如果是,就先釋放主線程,等下一次機會再繼續執行。

2.2 數據結構革新:從遞歸樹到鏈表

Fiber 用鏈表結構替代了遞歸調用棧,每個 Fiber 節點就是一個工作單元。每個節點包含三個關鍵指針:

  • child:指向第一個子節點
  • sibling:指向兄弟節點
  • return:指向父節點

這種結構讓 React 可以像 “遍歷鏈表” 一樣處理組件樹,而不是依賴 JavaScript 引擎的調用棧。遍歷過程可以隨時暫停,因為當前進度可以通過這些指針被完整記錄(比如 “當前處理到哪個節點,下一個該處理哪個節點”)。

// Fiber節點簡化結構
const fiberNode = {type: 'div',        // 節點類型stateNode: domNode, // 對應的DOM節點child: null,        // 第一個子節點sibling: null,      // 兄弟節點return: null,       // 父節點// ...其他屬性(優先級、更新隊列等)
};

2.3 工作循環:分階段處理任務

Fiber 架構將渲染過程分為兩個階段,實現了 “計算” 與 “執行” 的分離:

  1. 調度階段(Reconciliation)
    • 負責找出前后虛擬 DOM 的差異(Diffing)
    • 為需要更新的節點打上標記(新增、刪除、修改)
    • 可被中斷:如果有更高優先級任務,可以暫停當前計算
  2. 提交階段(Commit)
    • 根據調度階段的標記,執行實際的 DOM 操作
    • 調用組件生命周期函數或 Hooks(如useEffect
    • 不可中斷:確保 DOM 操作的原子性,避免頁面出現不一致狀態

這種分離設計,讓 React 可以在調度階段靈活調整執行順序,同時保證最終 DOM 更新的穩定性。

三、調度器(Scheduler):讓任務有輕重緩急

僅有 Fiber 結構還不夠,還需要一個智能的調度系統來決定:什么時候該執行哪個任務?

3.1 優先級分級機制

React 調度器根據任務的緊急程度,將其分為不同優先級:

  • Immediate:同步執行,最高優先級(如用戶輸入)
  • UserBlocking:用戶交互相關(如點擊事件),需在 25ms 內完成
  • Normal:普通更新(如網絡請求后的渲染),500ms 內完成
  • Low:低優先級任務(如列表預加載),1000ms 內完成
  • Idle:空閑時執行(如日志上報),沒有時間限制

3.2 時間切片(Time Slicing)

調度器利用瀏覽器的requestIdleCallbacksetTimeout模擬時間切片,確保每個任務單元的執行不超過 5ms-10ms。每處理完一個單元,就檢查是否超時或有更高優先級任務:

function workLoop() {// 只要有任務且未超時,就繼續執行while (nextUnitOfWork && !shouldYield()) {nextUnitOfWork = performUnitOfWork(nextUnitOfWork);}
}// 判斷是否需要讓出主線程
function shouldYield() {return performance.now() >= deadline; // deadline是當前時間切片的截止時間
}

這種機制保證了主線程不會被長時間占用,瀏覽器有機會處理用戶輸入和渲染,從而避免卡頓。

四、雙緩沖機制:提升渲染效率

Fiber 架構通過維護兩棵樹來優化渲染性能:

  • current 樹:當前顯示在頁面上的 Fiber 樹,與 DOM 節點一一對應
  • workInProgress 樹:正在構建的新樹,基于最新狀態計算

當開始更新時,React 會以 current 樹為基礎,創建 workInProgress 樹。對于不需要變更的節點,直接復用(通過alternate指針關聯);需要更新的節點,創建新的 Fiber 節點。全部計算完成后,只需將根節點的指針從 current 樹切換到 workInProgress 樹,就能完成一次高效的更新。

這種 “雙緩沖” 策略避免了頻繁創建和銷毀節點的開銷,同時確保了 DOM 更新的原子性(用戶不會看到中間狀態)。

五、新架構帶來的開發模式變革

Fiber 架構不僅解決了性能問題,更為 React 引入了新的開發能力,這些能力在 React 18 中得到了全面強化。

5.1 并發更新(Concurrent Updates)

在并發模式下,React 可以同時準備多個版本的 UI(比如快速輸入時的多個中間狀態),但只提交最終版本。這使得應用能在復雜計算的同時保持響應性。

import { startTransition } from 'react';// 輸入框實時搜索示例
function Search() {const [input, setInput] = useState('');const [results, setResults] = useState([]);function handleChange(e) {setInput(e.target.value);// 標記搜索結果更新為低優先級startTransition(() => {setResults(searchApi(e.target.value));});}return (<div><input value={input} onChange={handleChange} /><ResultsList results={results} /></div>);
}

startTransition告訴 React:輸入框更新(setInput)是緊急的,而搜索結果更新(setResults)可以延遲,不會阻塞用戶輸入。

5.2 性能優化的最佳實踐

基于新架構的特性,我們可以采用更精準的優化策略:

  • 拆分組件:將大組件拆分為小組件,讓任務單元更細,便于中斷和恢復
  • 使用React.memo:減少不必要的重渲染,尤其適合列表項組件
  • 合理使用優先級 API:通過startTransitionuseDeferredValue區分緊急與非緊急更新
  • 虛擬滾動:對于超長列表,只渲染可視區域內的項

六、總結

Fiber 架構的意義遠不止于性能提升,它代表了 React 設計理念的轉變:

  • 以用戶體驗為中心:優先保證交互響應速度,而非追求代碼執行效率
  • 增量計算思想:將復雜任務分解為可增量處理的單元,適應瀏覽器的工作機制
  • 彈性設計:通過優先級和中斷機制,讓應用能靈活應對不同運行時環境

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

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

相關文章

【JavaSE五天速通|第三篇】常用API與日期類篇

適合有其他語言基礎想快速入門JavaSE的。用的資料是 Java入門基礎視頻教程 &#xff0c;從中摘取了筆者認為與其他語言不同或需要重點學習的內容 常用API與日期類只需要有印象即可&#xff0c;用到了再來這查 day04 常用API 一、StringBuilder類 StringBuilder代表可變字符…

K8s學習筆記(二) Pod入門與實戰

1 K8s核心資源Pod 1.1 Pod是什么&#xff1f; 官方文檔&#xff1a;Pod | Kubernetes Pod 是 Kubernetes&#xff08;k8s&#xff09;中最小的部署與調度單元&#xff0c;并非直接運行容器&#xff0c;而是對一個或多個 “緊密關聯” 容器的封裝。 核心特點可簡單總結為 3 …

用 Python 調用 Bright Data MCP Server:在 VS Code 中實現實時網頁數據抓取

用 Python 調用 Bright Data MCP Server&#xff1a;在 VS Code 中實現實時網頁數據抓取&#xff0c;本文介紹了Bright Data的Web MCP Server&#xff0c;這是一款能實現實時、結構化網頁數據訪問的API&#xff0c;適用于AI應用等場景。其支持靜態與動態網頁&#xff0c;前3個月…

SPSS繪制ROC曲線并計算靈敏度、特異度

SPSS繪制ROC曲線并計算靈敏度、特異度。 &#xff08;1&#xff09;繪制ROC曲線&#xff1a; 輸入&#xff1a;預測值、受試者標簽。 在SPSS中點擊“分析”-“分類”-“ROC曲線” 變量輸入&#xff1a;檢驗變量輸入預測值&#xff0c;狀態變量輸入受試者標簽&#xff0c;如果標…

Modbus協議原理與Go語言實現詳解

目錄 Modbus協議概述協議架構與通信模式Modbus數據模型Modbus協議幀格式功能碼詳解Go Modbus庫完整實現高級應用示例調試與故障排除 Modbus協議概述 Modbus是一種串行通信協議&#xff0c;由Modicon公司&#xff08;現施耐德電氣&#xff09;于1979年開發&#xff0c;用于PL…

下載CentOS 7——從阿里云上下載不同版本的 CentOS 7

沒有廢話&#xff0c;直接上干貨。跟著圖片教程&#xff0c;一步一步來就行。 想下載其它版本的&#xff0c;自己可以再選擇其它的就行。 想省事的朋友可以直接點擊: 1、下載頁面鏈接 2、CentOS-7-x86_64-DVD-2207-02(4.4GB).iso

SpringBoot -原理篇

文章目錄配置優先級Bean管理獲取beanbean作用域第三方beanSpringBoot原理起步依賴自動配置自動配置原理方案源碼跟蹤原理分析 Conditional案例&#xff08;自定義starter&#xff09;案例&#xff08;自定義starter分析&#xff09;案例&#xff08;自定義starter實現&#xff…

JavaScript與jQuery:從入門到面試的完整指南

JavaScript與jQuery&#xff1a;從入門到面試的完整指南 第一部分&#xff1a;JavaScript基礎 1.1 JavaScript簡介 JavaScript是一種輕量級的解釋型編程語言&#xff0c;主要用于Web開發&#xff0c;可以為網頁添加交互功能。它是ECMAScript規范的一種實現。 // 第一個JavaScri…

解決:Ubuntu、Kylin、Rocky系統中root用戶忘記密碼

解決Linux系統中root用戶忘記密碼 Ubuntu2204 重啟電腦&#xff0c;啟動時&#xff0c;長按Shift鍵&#xff08;對于 BIOS 系統&#xff09;或 Esc 鍵&#xff08;對于 UEFI 系統&#xff09;進入GRUB菜單 步驟1&#xff1a;重啟Ubuntu系統&#xff0c;長按Shift鍵進入Ubuntu…

ENVI系列教程(二)——自定義坐標系(北京 54、西安 80、2000 坐標系)

目錄 1 概述 1.1 地理投影的基本原理 1.2 國內坐標系介紹 1.3 參數的獲取 2 詳細操作步驟 2.1 添加橢球體 2.2 添加基準面 2.3 定義坐標系 2.4 使用自定義坐標系 1 概述 1.1 地理投影的基本原理 常用到的地圖坐標系有 2 種,即地理坐標系和投影坐標系。地理坐標系是…

一種基于因果干預的少樣本學習的故障診斷模型

一、研究背景與問題 ?工業背景?:機械故障診斷對工業系統安全至關重要,但實際中故障樣本稀少,難以訓練傳統深度學習模型。 ?現有問題?: 當前少樣本學習(FSL)方法大多基于相關性而非因果關系建模,容易學習到偽相關特征,導致模型可解釋性差、泛化能力弱。 跨組件故障診…

機器視覺光源的尺寸該如何選型的方法

機器視覺光源的尺寸該如何選型的方法&#x1f3af;機器視覺光源的尺寸選型的方法&#x1f3af;一、選型案例&#x1f3af;二、照射方式&#x1f3af;三、鏡頭選擇&#x1f3af;四、光源架構光源的工作距離與視野大小&#x1f3af;五、總結&#xff1a;光源選型 —— 機器視覺檢…

HTML新屬性

HTML5引入了許多新屬性&#xff0c;旨在增強語義化、交互性和多媒體支持。以下是一些重要的新屬性及其用途分類&#xff1a;語義化與結構屬性data-*&#xff1a;自定義數據屬性&#xff0c;允許開發者存儲額外信息&#xff08;如data-id"123"&#xff09;。hidden&am…

從工地到鏈上:一個土建人的 Web3 轉行經歷

Web3 的風&#xff0c;終究還是吹到了土建行業。2017 年&#xff0c;土建專業&#xff08;給排水工程&#xff09;的劉正源偶然看到一則關于比特幣的新聞&#xff0c;被它背后的經濟模型與技術架構深深震撼。到了 2021 年&#xff0c;他在工地上再次聽人提起區塊鏈&#xff0c;…

20250914-03: Langchain概念:提示模板+少樣本提示

20250914-03: Langchain概念&#xff1a;提示模板少樣本提示 聊天模型 消息 提示 結構化輸出 &#x1f3af; 學習目標 掌握如何“喂給模型正確的輸入”并“解析出想要的輸出”。 &#x1f517; 核心概念 ?聊天模型&#xff08;ChatModel&#xff09;?消息&#xff08;M…

【AI推理部署】Docker篇04—Docker自動構建鏡像

Docker 自動構建鏡像1. Dockfile 編寫2. 鏡像使用使用 Dockerfile 構建鏡像 Dockerfile 其實就是把我們前面的一系列安裝、配置命令寫到一個文件中&#xff0c;通過 docker build 命令&#xff0c;一鍵完成鏡像的構建。接下來&#xff0c;我們以 bitnami/pytorch:2.1.1 作為基礎…

LeetCode 674.最長連續遞增序列

給定一個未經排序的整數數組&#xff0c;找到最長且 連續遞增的子序列&#xff0c;并返回該序列的長度。 連續遞增的子序列 可以由兩個下標 l 和 r&#xff08;l < r&#xff09;確定&#xff0c;如果對于每個 l < i < r&#xff0c;都有 nums[i] < nums[i 1] &am…

貪心算法java

貪心算法簡介貪心算法是一種在每一步選擇中都采取在當前狀態下最優&#xff08;局部最優&#xff09;的選擇&#xff0c;從而希望導致結果是全局最優的算法。貪心算法通常用于解決最優化問題&#xff0c;如最短路徑、最小生成樹、任務調度等。貪心算法的基本步驟問題分析&#…

【華為OD】解鎖犯罪時間

【華為OD】解鎖犯罪時間 題目描述 警察在偵破一個案件時&#xff0c;得到了線人給出的可能犯罪時間&#xff0c;形如"HH:MM"表示的時刻。根據警察和線人的約定&#xff0c;為了隱蔽&#xff0c;該時間是修改過的&#xff0c;解密規則為&#xff1a;利用當前出現過的數…

基于linux操作系統的mysql安裝

一、檢查自己的操作系統是否已經有存在的mysql 1.存在 2.不存在 二、基于操作系統不存在mysql,找官方yum源 網址&#xff1a; Index of /232905https://repo.mysql.com/ 網站打開是這樣 看看自己的操作系統是哪個版本&#xff0c;再下載哪個版本&#xff0c;如果和我一樣裝…