43. Fiber 架构解决了什么问题?(可中断的异步渲染、时间切片)
Fiber 架构概述
Fiber 是 React 16 引入的新架构,主要解决了传统 React 渲染过程中的阻塞问题。
传统 React 的问题
// 传统 React 的问题:同步渲染阻塞
function TraditionalRender() {
// 大量组件渲染
const components = Array.from({ length: 10000 }, (_, i) => (
<ExpensiveComponent key={i} data={i} />
))
return <div>{components}</div>
}
// 问题:
// 1. 渲染过程不可中断
// 2. 长时间渲染会阻塞主线程
// 3. 用户交互无法响应
// 4. 动画卡顿
Fiber 的解决方案
// Fiber 架构:可中断的异步渲染
function FiberRender() {
const [data, setData] = useState([])
useEffect(() => {
// 大量数据渲染
const largeData = Array.from({ length: 10000 }, (_, i) => i)
setData(largeData)
}, [])
return (
<div>
{data.map((item) => (
<ExpensiveComponent key={item} data={item} />
))}
</div>
)
}
// Fiber 的优势:
// 1. 渲染过程可中断
// 2. 优先级调度
// 3. 时间切片
// 4. 并发渲染
时间切片 (Time Slicing)
时间切片原理
// 时间切片:将渲染工作分割成小块
class TimeSlicing {
constructor() {
this.timeSlice = 5 // 5ms 时间片
this.workQueue = []
this.isWorking = false
}
// 添加工作到队列
addWork(work) {
this.workQueue.push(work)
if (!this.isWorking) {
this.scheduleWork()
}
}
// 调度工作
scheduleWork() {
this.isWorking = true
const startTime = performance.now()
while (this.workQueue.length > 0) {
const work = this.workQueue.shift()
work()
// 检查时间片是否用完
if (performance.now() - startTime > this.timeSlice) {
// 时间片用完,让出控制权
setTimeout(() => this.scheduleWork(), 0)
return
}
}
this.isWorking = false
}
}
// 使用示例
const timeSlicing = new TimeSlicing()
function renderComponent(component) {
timeSlicing.addWork(() => {
// 渲染组件
render(component)
})
}
实际应用
// 使用 startTransition 进行时间切片
import { startTransition, useState } from 'react'
function SearchResults({ query }) {
const [results, setResults] = useState([])
const [isPending, setIsPending] = useState(false)
useEffect(() => {
if (!query) return
setIsPending(true)
// 使用 startTransition 标记非紧急更新
startTransition(() => {
const newResults = searchData(query) // 大量计算
setResults(newResults)
setIsPending(false)
})
}, [query])
return (
<div>
{isPending && <div>搜索中...</div>}
{results.map((result) => (
<div key={result.id}>{result.title}</div>
))}
</div>
)
}
优先级调度
优先级系统
// React 的优先级系统
const PriorityLevels = {
Immediate: 1, // 立即执行(用户输入)
UserBlocking: 2, // 用户阻塞(点击、悬停)
Normal: 3, // 普通优先级(数据更新)
Low: 4, // 低优先级(后台任务)
Idle: 5, // 空闲时执行(分析、预加载)
}
// 优先级调度器
class PriorityScheduler {
constructor() {
this.workQueues = {
[PriorityLevels.Immediate]: [],
[PriorityLevels.UserBlocking]: [],
[PriorityLevels.Normal]: [],
[PriorityLevels.Low]: [],
[PriorityLevels.Idle]: [],
}
this.isWorking = false
}
// 添加工作
addWork(work, priority = PriorityLevels.Normal) {
this.workQueues[priority].push(work)
this.scheduleWork()
}
// 调度工作
scheduleWork() {
if (this.isWorking) return
this.isWorking = true
// 按优先级执行工作
for (
let priority = PriorityLevels.Immediate;
priority <= PriorityLevels.Idle;
priority++
) {
const queue = this.workQueues[priority]
while (queue.length > 0) {
const work = queue.shift()
work()
// 检查是否需要让出控制权
if (this.shouldYield()) {
this.isWorking = false
setTimeout(() => this.scheduleWork(), 0)
return
}
}
}
this.isWorking = false
}
// 检查是否应该让出控制权
shouldYield() {
// 检查是否有高优先级工作
for (
let priority = PriorityLevels.Immediate;
priority < PriorityLevels.Normal;
priority++
) {
if (this.workQueues[priority].length > 0) {
return true
}
}
// 检查时间片
return performance.now() - this.startTime > 5
}
}
实际应用
// 使用不同优先级的更新
function Component() {
const [count, setCount] = useState(0)
const [urgent, setUrgent] = useState(false)
const [background, setBackground] = useState('')
const handleClick = () => {
// 高优先级更新:用户交互
setUrgent(true)
// 普通优先级更新:数据更新
setCount(count + 1)
// 低优先级更新:后台任务
startTransition(() => {
setBackground('updated')
})
}
return (
<div>
<button onClick={handleClick}>更新</button>
<p>Count: {count}</p>
<p>Urgent: {urgent ? 'Yes' : 'No'}</p>
<p>Background: {background}</p>
</div>
)
}
并发渲染
并发渲染原理
// 并发渲染:同时处理多个更新
class ConcurrentRenderer {
constructor() {
this.workInProgress = null
this.current = null
this.pendingUpdates = []
}
// 开始渲染
startRender(component) {
this.workInProgress = this.createFiber(component)
this.scheduleWork()
}
// 调度工作
scheduleWork() {
// 使用 requestIdleCallback 在空闲时执行
if (window.requestIdleCallback) {
window.requestIdleCallback(this.performWork.bind(this))
} else {
setTimeout(this.performWork.bind(this), 0)
}
}
// 执行工作
performWork(deadline) {
while (this.workInProgress && deadline.timeRemaining() > 0) {
this.workInProgress = this.performUnitOfWork(this.workInProgress)
}
if (this.workInProgress) {
// 还有工作未完成,继续调度
this.scheduleWork()
} else {
// 工作完成,提交更新
this.commitWork()
}
}
// 执行单个工作单元
performUnitOfWork(fiber) {
// 处理当前 fiber
this.beginWork(fiber)
// 返回下一个要处理的 fiber
return this.nextFiber(fiber)
}
}
实际应用
// 使用并发特性
import { startTransition, useDeferredValue } from 'react'
function App() {
const [query, setQuery] = useState('')
const [results, setResults] = useState([])
// 延迟更新查询结果
const deferredQuery = useDeferredValue(query)
useEffect(() => {
if (deferredQuery) {
startTransition(() => {
const newResults = searchData(deferredQuery)
setResults(newResults)
})
}
}, [deferredQuery])
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="搜索..."
/>
<SearchResults results={results} />
</div>
)
}