React Fiber 架構(gòu)解決頁(yè)面卡頓問(wèn)題的全過(guò)程
React Fiber 架構(gòu)詳解:為什么它能解決頁(yè)面卡頓問(wèn)題?

本文從問(wèn)題與目標(biāo)、核心數(shù)據(jù)結(jié)構(gòu)、調(diào)度與中斷、渲染階段與提交階段、優(yōu)先級(jí)與 lanes、并發(fā)特性到常見(jiàn)誤區(qū)與優(yōu)化建議,全景式拆解 React Fiber,為何它能夠顯著降低交互卡頓并提升可響應(yīng)性。
TL;DR
- Fiber 將渲染過(guò)程切成可中斷的小任務(wù)并在合適的時(shí)機(jī)繼續(xù)執(zhí)行
- 通過(guò)優(yōu)先級(jí)與 lanes 模型,優(yōu)先處理緊急交互,延遲非關(guān)鍵更新
- 渲染分兩階段:可打斷的 render 與一次性提交的 commit,DOM 變更集中且短促
- 調(diào)度器以時(shí)間片與讓渡機(jī)制避免長(zhǎng)任務(wù)阻塞主線(xiàn)程,從而減少卡頓
- 并發(fā)特性如
useTransition、Suspense、選擇性水合都建立在 Fiber 能力之上
卡頓的來(lái)源與架構(gòu)目標(biāo)
- 來(lái)源:長(zhǎng)耗時(shí)任務(wù)阻塞事件處理與動(dòng)畫(huà)幀,渲染與計(jì)算無(wú)法及時(shí)讓出主線(xiàn)程
- 目標(biāo):將更新拆解為細(xì)粒度單元,基于優(yōu)先級(jí)可中斷、可恢復(fù)且可重試的執(zhí)行模型
- 兼容:保留類(lèi)組件與函數(shù)組件的語(yǔ)義,支持 SSR、Hydration 與后續(xù)擴(kuò)展
Fiber 的核心數(shù)據(jù)結(jié)構(gòu)
每個(gè) Fiber 對(duì)應(yīng)一次渲染過(guò)程中的“工作單元”,以鏈表樹(shù)結(jié)構(gòu)組織:
type Lane = number
interface Fiber {
tag: number
key: null | string
type: any
stateNode: any
return: Fiber | null
child: Fiber | null
sibling: Fiber | null
alternate: Fiber | null
lanes: Lane
flags: number
memoizedProps: any
memoizedState: any
updateQueue: any
}child與sibling:鏈?zhǔn)綐?shù)遍歷更適合增量執(zhí)行alternate:當(dāng)前樹(shù)與待提交的工作樹(shù)雙緩沖切換lanes與flags:控制優(yōu)先級(jí)與記錄副作用
兩階段模型:render 與 commit
- render 階段:構(gòu)建工作樹(shù)、計(jì)算變更列表,允許中斷與恢復(fù)
- commit 階段:一次性將變更應(yīng)用到 DOM 與副作用,盡量短小
- 好處:長(zhǎng)計(jì)算不阻塞瀏覽器事件與動(dòng)畫(huà),提交階段集中且可控
調(diào)度與時(shí)間片:避免長(zhǎng)任務(wù)阻塞
- 以切片執(zhí)行的工作循環(huán)進(jìn)行遍歷,接近以下偽代碼:
let workInProgress: Fiber | null = null
function shouldYield() {
return performance.now() >= deadline
}
function workLoop() {
while (workInProgress && !shouldYield()) {
workInProgress = performUnitOfWork(workInProgress)
}
if (workInProgress) scheduleNextTick(workLoop)
}- 通過(guò)
shouldYield在每個(gè)單元之間檢查是否需要讓渡控制權(quán) - 調(diào)度器依據(jù)任務(wù)的 lanes 與瀏覽器空閑時(shí)間安排后續(xù)執(zhí)行
優(yōu)先級(jí)與 lanes:誰(shuí)更重要先做誰(shuí)
- lanes 是位掩碼表示的多優(yōu)先級(jí)融合模型
- 高優(yōu)先級(jí)任務(wù)包含輸入響應(yīng)與選擇性水合,低優(yōu)先級(jí)用于非關(guān)鍵渲染
- 多任務(wù)可歸并到 lanes,調(diào)度器據(jù)此選擇下一個(gè)單元
為什么能緩解卡頓
- 將不可打斷的同步樹(shù)遍歷改造為可暫停的單元工作
- 遇到輸入事件或動(dòng)畫(huà)幀時(shí)及時(shí)讓渡,保障主線(xiàn)程響應(yīng)
- 區(qū)分緊急與非緊急更新,減少無(wú)關(guān)變更搶占時(shí)間片
- commit 階段將 DOM 變更批量一次性應(yīng)用,縮短布局與繪制沖擊
并發(fā)特性與 Fiber 的關(guān)系
useTransition與startTransition:將更新標(biāo)記為非緊急,排在緊急交互之后Suspense:在資源未就緒時(shí)掛起某些子樹(shù),避免阻塞頁(yè)面可交互區(qū)域- 選擇性水合:SSR 下優(yōu)先水合用戶(hù)交互路徑上的組件
useDeferredValue:推遲昂貴的派生計(jì)算以保證輸入響應(yīng)速度
工作循環(huán)與單元執(zhí)行
function performUnitOfWork(fiber: Fiber): Fiber | null {
beginWork(fiber)
if (fiber.child) return fiber.child
let node: Fiber | null = fiber
while (node) {
completeWork(node)
if (node.sibling) return node.sibling
node = node.return
}
return null
}
beginWork生成子節(jié)點(diǎn)與比較 propscompleteWork構(gòu)建副作用列表與準(zhǔn)備提交信息- 在每個(gè)單元之間檢查讓渡條件,實(shí)現(xiàn)可中斷的深度優(yōu)先遍歷
典型場(chǎng)景與實(shí)踐
- 大列表渲染:結(jié)合虛擬滾動(dòng)與并發(fā)更新,輸入滾動(dòng)時(shí)保持流暢
- 復(fù)雜表單輸入:將非關(guān)鍵重排與昂貴計(jì)算置于過(guò)渡更新
- 數(shù)據(jù)獲取與占位:用
Suspense顯示骨架屏并保持交互域可用 - SSR 水合:優(yōu)先水合導(dǎo)航與交互區(qū)域,其余延后進(jìn)行
常見(jiàn)誤區(qū)
- 認(rèn)為 Fiber 自動(dòng)優(yōu)化所有卡頓。若 render 執(zhí)行中包含長(zhǎng)耗時(shí)同步邏輯,仍會(huì)占用時(shí)間片
- 在 commit 階段做重計(jì)算或強(qiáng)制同步布局會(huì)導(dǎo)致幀率下降
- 不當(dāng)?shù)念l繁狀態(tài)變更會(huì)增加任務(wù)競(jìng)爭(zhēng),需進(jìn)行歸并與降頻
- 忽視 keys 與結(jié)構(gòu)穩(wěn)定性會(huì)增加無(wú)效重建
性能建議
- 用
useTransition或批處理分離緊急與非緊急更新 - 將昂貴計(jì)算移動(dòng)到 memo 化或后臺(tái)任務(wù),減少 render 成本
- 控制 commit 的 DOM 變更數(shù)量與粒度,避免反復(fù)測(cè)量布局
- 優(yōu)化列表與表格,采用虛擬化與分塊渲染
- 使用 Profiler 與 Performance 工具定位長(zhǎng)任務(wù)與熱點(diǎn)組件
總結(jié)
Fiber 的核心價(jià)值是以可中斷、可恢復(fù)的增量執(zhí)行模型替代不可分割的同步渲染。它結(jié)合優(yōu)先級(jí)與時(shí)間片調(diào)度,將緊急交互放在首位,并通過(guò)分階段提交降低 DOM 變更的集中沖擊。理解 Fiber 的數(shù)據(jù)結(jié)構(gòu)、工作循環(huán)與并發(fā)特性,有助于在真實(shí)項(xiàng)目中系統(tǒng)性地治理卡頓問(wèn)題并提升整體可響應(yīng)性。
進(jìn)階解析:優(yōu)先級(jí)體系與 lanes 細(xì)節(jié)
- React 18 將早期的 Scheduler 優(yōu)先級(jí)(Immediate/UserBlocking/Normal/Low/Idle)抽象為 lanes;一個(gè)更新可以占用多個(gè) lanes
- lanes 使用位掩碼,便于合并與比較;渲染時(shí)選擇最高優(yōu)先級(jí)的 lane 作為下一幀的工作目標(biāo)
- 離散事件(點(diǎn)擊、輸入)通常賦予高優(yōu)先級(jí);連續(xù)事件(滾動(dòng)、鼠標(biāo)移動(dòng))優(yōu)先級(jí)較低并可被打斷
- 協(xié)調(diào)策略:
- 合并同類(lèi)型低優(yōu)更新,減少重復(fù)工作
- 當(dāng)高優(yōu)更新到來(lái)時(shí),打斷當(dāng)前 render,保存現(xiàn)場(chǎng)并優(yōu)先處理高優(yōu)
- 超時(shí)控制避免低優(yōu)任務(wù)長(zhǎng)期饑餓
雙緩沖與副作用標(biāo)記
- 雙緩沖:
current指向已提交的樹(shù);workInProgress是正在構(gòu)建的工作樹(shù),二者通過(guò)alternate互為鏡像 - 副作用標(biāo)記(
flags)記錄節(jié)點(diǎn)的變更類(lèi)型(Placement/Update/Deletion 等) - render 階段構(gòu)建副作用鏈表,commit 階段按序遍歷執(zhí)行,確保 DOM 變更集中完成
被打斷的渲染如何恢復(fù)
- 渲染在單元邊界處可暫停,恢復(fù)時(shí)從上次的
workInProgress繼續(xù) - bailout:若某子樹(shù) props/state 未變化或
shouldComponentUpdate/React.memo判定無(wú)需更新,則跳過(guò)子樹(shù)計(jì)算 - 重試與掛起:配合
Suspense對(duì)未就緒數(shù)據(jù)的子樹(shù)進(jìn)行掛起,數(shù)據(jù)可用后再重試該子樹(shù)
并發(fā)渲染與用戶(hù)體驗(yàn)
- 并發(fā)渲染不是并行執(zhí)行,而是允許在同一線(xiàn)程的不同時(shí)間片中交替推進(jìn)多個(gè)樹(shù)的渲染
- 用戶(hù)可見(jiàn)區(qū)域優(yōu)先:借助優(yōu)先級(jí)與選擇性水合,優(yōu)先渲染交互路徑上的組件,降低首屏交互延遲
- 資源阻塞治理:
Suspense將依賴(lài)資源的子樹(shù)掛起,用占位/骨架提升感知速度,避免整頁(yè)卡住
調(diào)度器內(nèi)部要點(diǎn)
- 時(shí)間片長(zhǎng)度根據(jù)環(huán)境動(dòng)態(tài)調(diào)整,瀏覽器與 Node 環(huán)境采用不同的定時(shí)/消息通道策略
- 在支持的瀏覽器中可利用
navigator.scheduling.isInputPending()判斷是否存在待處理的輸入事件,從而更積極地讓渡 - 微任務(wù)與宏任務(wù)配合,確保任務(wù)隊(duì)列與渲染隊(duì)列之間的公平性,避免某一方長(zhǎng)時(shí)間獨(dú)占
代碼示例:用過(guò)渡更新緩解輸入卡頓
import { useMemo, useTransition, useState } from 'react'
export default function FilterList({ items }: { items: string[] }) {
const [query, setQuery] = useState('')
const [isPending, startTransition] = useTransition()
const filtered = useMemo(() => {
const q = query.toLowerCase()
return items.filter(i => i.toLowerCase().includes(q))
}, [items, query])
return (
<div>
<input
value={query}
onChange={e => {
const v = e.target.value
startTransition(() => setQuery(v))
}}
placeholder="輸入過(guò)濾關(guān)鍵詞"
/>
{isPending && <span>計(jì)算中…</span>}
<ul>
{filtered.map(i => <li key={i}>{i}</li>)}
</ul>
</div>
)
}- 將
setQuery放入startTransition,把過(guò)濾計(jì)算標(biāo)記為非緊急更新,輸入響應(yīng)優(yōu)先不卡頓
代碼示例:Suspense 與數(shù)據(jù)就緒的掛起
function UserCard() {
const user = useUserResource() // 內(nèi)部拋出 Promise,待數(shù)據(jù)就緒再繼續(xù)渲染
return <div>{user.name}</div>
}
export default function Page() {
return (
<Suspense fallback={<Skeleton />}>
<UserCard />
</Suspense>
)
}- 未就緒時(shí)渲染
fallback,就緒后恢復(fù)渲染子樹(shù);配合 Fiber 的可中斷模型提升感知速度
SSR 與選擇性水合
- React 18 的流式 SSR 將 HTML 分塊輸出,客戶(hù)端根據(jù)用戶(hù)交互路徑優(yōu)先水合必要組件
- 選擇性水合避免一次性水合整棵樹(shù)導(dǎo)致的主線(xiàn)程擁塞,優(yōu)先保證可點(diǎn)擊/可輸入?yún)^(qū)域
診斷與優(yōu)化清單
- 渲染開(kāi)銷(xiāo):
- 使用 Profiler 捕獲長(zhǎng)耗時(shí)組件
- 用
memo/useMemo/useCallback控制派生與重建
- 提交階段:
- 合并 DOM 變更,避免在 commit 中進(jìn)行昂貴計(jì)算或強(qiáng)制布局
- 減少同步測(cè)量與多次讀寫(xiě)交錯(cuò)導(dǎo)致的布局抖動(dòng)
- 任務(wù)競(jìng)爭(zhēng):
- 將非關(guān)鍵更新放入
useTransition或批處理 - 對(duì)頻繁狀態(tài)用節(jié)流/防抖或批量歸并
- 將非關(guān)鍵更新放入
- 結(jié)構(gòu)穩(wěn)定性:
- 正確使用
key,減少無(wú)謂 diff 與重排 - 列表/表格采用虛擬化與分塊渲染
- 正確使用
常見(jiàn)反模式與替代方案
- 在渲染或副作用中執(zhí)行大循環(huán)或密集計(jì)算,可改為后臺(tái) Worker 或增量計(jì)算
- 在
useEffect中頻繁、同步地讀取布局并寫(xiě)入樣式,改為批量讀后批量寫(xiě)或轉(zhuǎn)移到動(dòng)畫(huà)幀 - 不區(qū)分緊急/非緊急更新導(dǎo)致輸入抖動(dòng),使用
startTransition分離
小結(jié)與實(shí)踐建議
- 評(píng)估場(chǎng)景:是否存在長(zhǎng)列表、復(fù)雜派生、頻繁交互或數(shù)據(jù)阻塞
- 策略組合:優(yōu)先級(jí)劃分 + 并發(fā)渲染 + 占位與水合 + 結(jié)構(gòu)優(yōu)化
- 工具鏈:Profiler、Performance、Lighthouse 聯(lián)合定位瓶頸,結(jié)合日志采樣觀察真實(shí)終端表現(xiàn)
到此這篇關(guān)于React Fiber 架構(gòu)解決頁(yè)面卡頓問(wèn)題的全過(guò)程的文章就介紹到這了,更多相關(guān)React Fiber 架構(gòu)頁(yè)面卡頓內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 深入理解React Fiber機(jī)制
- 深入理解React的Fiber架構(gòu)
- React 中的雙緩存 Fiber 樹(shù)機(jī)制詳解
- React Fiber中面試官最關(guān)心的技術(shù)話(huà)題
- React-three-fiber使用初體驗(yàn)
- React超詳細(xì)講述Fiber的使用
- React?Fiber構(gòu)建源碼解析
- React?Fiber構(gòu)建completeWork源碼解析
- React?Fiber原理深入分析
- React Fiber與調(diào)和深入分析
- React Fiber源碼深入分析
- React的Fiber的實(shí)現(xiàn), Vue為什么不需要Fiber
相關(guān)文章
TypeScript在React項(xiàng)目中的實(shí)戰(zhàn)應(yīng)用指南及技巧
在React項(xiàng)目中集成TypeScript可以顯著提升開(kāi)發(fā)體驗(yàn),通過(guò)類(lèi)型檢查減少運(yùn)行時(shí)錯(cuò)誤,提高代碼可維護(hù)性,這篇文章主要介紹了TypeScript在React項(xiàng)目中實(shí)戰(zhàn)應(yīng)用指南及技巧的相關(guān)資料,需要的朋友可以參考下2026-03-03
React-Native 橋接iOS原生開(kāi)發(fā)詳解
本篇文章主要介紹了React-Native 橋接iOS原生開(kāi)發(fā)詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
每天一個(gè)hooks學(xué)習(xí)之useUpdateEffect
這篇文章主要為大家介紹了每天一個(gè)hooks學(xué)習(xí)之useUpdateEffect使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05

