当前位置: 首页 > news >正文

React19 渲染流程

一、React 渲染架构

底层渲染流程大致可以分为两大阶段:render 阶段(Scheduler -> Reconciler)、commit 阶段(Renderer)

注意这里的 render 阶段和 Renderer 渲染器是两个东西!!!

主要的阶段可以总结为两个公式:

const state = reconcile(update); // 通过 reconciler 计算出最新的状态
const UI = commit(state); // 通过最新的 state 渲染出 UI

二、调度器(Scheduler):渲染的入口与优先级控制

Scheduler 类似于浏览器的原生 API requestIdleCallback。React 团队没有使用 requestIdleCallback 是因为考虑为兼容性问题。

Scheduler 是整个渲染执行链条的入口,负责:

  1. 将变更转化为任务
  2. 按优先级调度任务执行
  3. 支持时间切片与可中断渲染

虽然每一帧绘制时间约为 16.66ms,但是如果屏幕没有刷新,那么浏览器会安排长度为 50ms 左右的空闲时间。

研究表明,用户操作之后,100ms 以内的响应给用户的感觉都是瞬间发生,也就是说不会感受到延迟感,因此将空闲时间设置为 50,浏览器依然还剩下 50ms 可以处理用户的操作响应,不会让用户感到延迟,这就是我们面试题中常看到的浏览器渲染每帧的空闲时间。

  1. 更新任务被排队

当你调用 setStatedispatchstartTransition、事件触发更新时,React 内部会:

scheduleUpdateOnFiber(fiber, lane, eventTime)

这个函数是调度入口,它将更新附着在对应的 Fiber 上,并根据任务的 lane(内部优先级) 更新任务队列。

  1. 任务优先级系统(Lanes)

React 内部并不使用单一队列,而是用多 lane 机制。

优先级由 Scheduler 根据事件来源与延迟(expiration time)决定。

  1. 时间切片(Time Slicing)

Scheduler 会根据浏览器的空闲时间,决定是在当前帧继续执行还是 yield 给浏览器,这样协调器起点也是不同的:

  • performSyncWorkOnRoot(同步更新流程)
  • performConcurrentWorkOnRoot(并发更新流程)
// performSyncWorkOnRoot 会执行该方法
function workLoopSync(){while(workInProgress !== null){performUnitOfWork(workInProgress)}
}
// performConcurrentWorkOnRoot 会执行该方法
function workLoopConcurrent() {// shouldYield 表明任务是否可以中断// 如果 workInProgress 为 null,说明已经没有下一个 FiberNode,也就是说明整颗 Fiber tree 树构建完毕while (workInProgress !== null && !shouldYield()) {// performUnitOfWork创建下一个 FiberNode,并且将已创建的 FiberNode 连接起来(child、return、sibling),形成一个链表结构的 Fiber treeworkInProgress = performUnitOfWork(workInProgress); }
}

shouldYield 判断当前帧是否该让出,避免阻塞主线程。

  1. 中断 + 恢复机制

如果有更高优先级的任务,中断当前 render,后续在合适时机 ​恢复执行​。这样能确保交互响应不会被大更新阻塞。

三、协调器(Reconciler):Fiber 树的 diff 与标记

协调器的核心任务是:

  1. 对比新旧树,确定哪些节点变化
  2. 生成 workInProgress Fiber 树
  3. 标记变化(Placement、Update、Deletion)
  4. 不直接修改 DOM,而是将变化收集起来
  5. Fiber 数据结构

每一个组件在运行时都有一个 Fiber 节点:

  • 指向真实 DOM 实例
  • 链接 child / sibling / return 三个方向
  • 记录当前组件状态、props、更新队列、优先级等属性

这种结构不同于简单递归栈,它更像一颗​可分片执行的链表树​。

  1. Reconciler 工作循环 —— render 阶段

协调器是由 Scheduler 调度后执行的。React 会从 Root Fiber 开始 traverse。

a. beginWork

处理当前节点逻辑,根据类型(函数组件 / 类组件 / Fragment 等)判断需要构建哪些子 Fiber。

b. completeWork

在子节点构建完成后整合变化,把节点的更改标记写入 flags

// 深度优先遍历
function performUnitOfWork(fiberNode){// 省略 beginWork if(fiberNode.child){performUnitOfWork(fiberNode.child);}// 省略 CompleteWork if(fiberNode.sibling){performUnitOfWork(fiberNode.sibling);}
}

整个过程构成一个 ​双缓冲机制​:

  • current Fiber(当前渲染状态)
  • workInProgress Fiber(正在构建的树)

最终 workInProgress 树会用于提交阶段。

  1. 标记变化

协调器不会直接操作 DOM,而是根据差异为每个节点打上 flags:

  • Placement​:新节点插入
  • Update​:属性/文本内容更新
  • Deletion​:删除节点

这些标记会在提交阶段被 Renderer 读取。

四、渲染器(Renderer):真实环境应用变化

Renderer 是把协调阶段生成的变化同步应用到最终环境,比如:

  • 浏览器的 DOM
  • React Native 原生视图
  • 其他自定义渲染平台

React 通过隔离平台实现了 Renderer 的可插拔。相较于 render 阶段,此时 commit 阶段不可中断恢复。

  1. 提交阶段的三个子阶段

协调阶段完成后进入 ​commit 阶段​:

a. Before Mutation

执行 getSnapshotBeforeUpdate(类组件),记录焦点、selection(输入框光标)等。

commitBeforeMutationEffects(root, finishedWork)
// 读取旧的 DOM 状态

b. Mutation

真实 DOM 操作发生位置​,根据 flags 做:appendChild、removeChild、update 属性、插入节点等。

然后切换 Fiber Tree(也就是上面提到的双缓冲机制,两棵树互换)。

c. Layout

useLayoutEffect 的意义是:在 DOM 更新完成后,浏览器绘制之前,同步读取或修改布局。

执行 useLayoutEffect、componentDidMount、componentDidUpdate 的回调。

注意哦!!!这里虽然 DOM 已经变更了,但是浏览器页面​还没有 paint,下一步才是绘制​。

  1. 渲染器应用 DOM 改变

commitUpdate(domElement, updatePayload, type, oldProps, newProps)
// 调用一系列 DOM API 为元素属性更新赋值

这里 paint 之后,才会执行 useEffect(异步)的回调。

所以如果需要操作 DOM ,要在 useLayoutEffect 钩子执行。

http://www.jsqmd.com/news/319121/

相关文章:

  • GIT中分支合并的方法
  • 作为AI应用架构师,我每天都在用的8个核心技能
  • Gemini3ProImage(nano banana 2 )异步调用接口(API)生成图片
  • P1114 “非常男女”计划
  • 键盘按键测试
  • 在计算属性中获取 Vuex 状态是标准做法(附:Vue 3 计算属性详解及和 watch 对比)
  • VSCode如何使用claude code(VS Code + Claude API 详细教程)(API 配置图文全攻略)
  • 深度学习篇--- transform(转换器)
  • 【双端队列bfs】
  • 算法入门打卡Day2___滑动窗口法、螺旋矩阵、前缀和(区间和问题,开发商购买土地问题)、数组与容器的区别
  • 【Vue知识点总结】Vue 路由中的 hidden: true:路由控制技巧
  • AI模型训练:数据获取与增强
  • 子网划分原理、等长子网划分方法、等长子网划分实验
  • curl使用
  • 芒格的“锚定效应“警示:避免固有思维陷阱
  • 如何使用 Markdown 和思维导图可视化你的想法
  • 2025年上海地下室渗水维修TOP5专业服务商深度评测
  • 系统思考:以客户为中心
  • 曾经火爆的捕鱼游戏:一套完整的概率操控、经济循环与用户留存设计方案
  • 防止3.3v数字电源干扰到模拟电源3.3v 需做隔离,这里怎么实现
  • 旅游小程序设计毕业论文+PPT(附源代码+演示视频)
  • 基于multisim的声音识别的蚊子雌雄判别专用电路设计
  • 一个后台管理所有 AI:手把手教你搭建属于自己的 AI 中转站(CLIProxyAPI版)
  • 程序员如何利用AI进行资源调度
  • YOLO26涨点改进 | 全网独家创新/Conv篇 | AAAI 2025 | PConv新型风车形卷积和SPConv二次创新改进(移动风车卷积,使它充分活跃起来),增强特征提取,扩大感受野
  • 基于multisim的10min数字秒表设计
  • 从数据孤岛到系统承载:星际荣耀航天研发中的单一数据源工程实践
  • Nginx基础
  • 【LeetCode刷题】二叉树的中序遍历
  • nacos作为dubbo服务注册中心