chst365's blog chst365's blog
首页
  • Git
  • 网络
  • 操作系统
  • 浏览器
  • webpack
  • JavaScript
  • TypeScript
  • 性能
  • 工程化
  • React
  • 编程题
  • React技术揭秘
  • 算法
  • Node
  • 编码解码
  • NodeJS系列
  • Linux系列
  • JavaScript系列
  • HTTP系列
  • GIT系列
  • ES6系列
  • 设计模式系列
  • CSS系列
  • 小程序系列
  • 数据结构与算法系列
  • React系列
  • Vue3系列
  • Vue系列
  • TypeScript系列
  • Webpack系列
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

chst365

DIV工程师
首页
  • Git
  • 网络
  • 操作系统
  • 浏览器
  • webpack
  • JavaScript
  • TypeScript
  • 性能
  • 工程化
  • React
  • 编程题
  • React技术揭秘
  • 算法
  • Node
  • 编码解码
  • NodeJS系列
  • Linux系列
  • JavaScript系列
  • HTTP系列
  • GIT系列
  • ES6系列
  • 设计模式系列
  • CSS系列
  • 小程序系列
  • 数据结构与算法系列
  • React系列
  • Vue3系列
  • Vue系列
  • TypeScript系列
  • Webpack系列
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 浏览器

  • webpack

  • TypeScript

  • 性能

  • 工程化

  • React

  • JavaScript

  • 编程题

  • React技术揭秘

    • React理念
    • React新老架构
      • React15架构
        • Reconciler(协调器)
        • Renderer(渲染器)
        • React15架构的缺点
      • React16架构
        • Scheduler(调度器)
        • Reconciler(协调器)
        • Renderer(渲染器)
    • Fiber
    • 前置知识
    • render阶段
    • commit阶段
    • Diff算法
    • 状态更新
    • Hooks
  • 算法

  • 前端
  • React技术揭秘
chst365
2022-09-14
目录

React新老架构

# React15架构

React15架构可分两层:

  • Reconciler(协调器):负责找出变化的组件
  • Renderer(渲染器):负责将变化的组件渲染到页面上

# Reconciler(协调器)

在React中可通过this.setState、this.forceUpdate、ReactDOM.render等API触发更新。 每当有更新发生时,Reconciler会做如下工作:

  • 调用函数组件或class组件的render方法,将返回的JSX转化为虚拟DOM
  • 将虚拟DOM和上次更新时的虚拟DOM对比
  • 通过对比找出本次更新中变化的虚拟DOM
  • 通知Renderer将变化的虚拟DOM渲染到页面上 可在这里 (opens new window)看到React官方对Reconciler的解释

# Renderer(渲染器)

由于React支持跨平台,所以不同平台有不同的Renderer。我们最熟悉的是负责在浏览器环境渲染的Renderer——ReactDOM (opens new window) 除此之外,还有:

  • ReactNative (opens new window)渲染器,渲染App原生组件
  • ReactTest (opens new window)渲染器,渲染出纯js对象用于测试
  • ReactArt (opens new window)渲染器,渲染到Canvas,SVG或VML(IE8)

可在这里 (opens new window)看到React官方对Renderer的解释

# React15架构的缺点

在Reconciler中,mount的组件会调用mountComponent (opens new window), update的组件会调用updateComponent (opens new window)。 这两个方法都会递归更新子组件。 递归更新的缺点:一旦开始,中途无法中断。当层级很深时,递归更新时间超过16ms,用户交互就会卡顿。

那么React15的架构支持异步更新吗?我们来看一个例子: 初始化时state.count=1,每次点击按钮state.count++ 列表中3个元素的值分别为1,2,3乘以state.count的结果 用红色标注了更新的步骤 我们看到,Reconciler和Renderer是交替工作的。 由于整个过程都是同步的,所以在用户看来所有DOM是同时更新的。 我们模拟下,如果中途中断更新会怎么样(React15并不会中断进行中的更新)? 可看到,当第一个li完成更新时中断更新,即步骤3完成后中断更新,此时后面的步骤都还未执行。 用户本来期望123变成246,。实际却看见更新不完全的DOM(即223) 为此,React重写了整个架构。

# React16架构

React16架构可分三层:

  • Scheduler(调度器)——调度任务优先级,高优先任务优先进入Reconciler
  • Reconciler(协调器):负责找出变化的组件
  • Renderer(渲染器):负责将变化的组件渲染到页面上

# Scheduler(调度器)

既然我们以浏览器是否有剩余时间作为任务中断的标准,那么我们需要一种机制:当浏览器有剩余时间时通知我们。 其实部分浏览器已实现这个API,就是requestldleCallback (opens new window)。 但由于以下因素,React放弃使用:

  • 浏览器兼容性
  • 触发频率不稳定,受多因素影响。如当浏览器切换tab后,之前tab注册的requestldleCallback触发频率会变很低

基于以上原因,React实现了功能更完备的requestIdleCallback polyfill,这就是Scheduler。 除了在空闲时触发回调的功能外,Scheduler还提供了多种调度优先级供任务设置。 Scheduler (opens new window)是独立于React的库

# Reconciler(协调器)

React15中Reconciler是递归处理虚拟DOM的。让我们看看React16的Reconciler (opens new window) 可看到,更新工作从递归变成了可中断的循环过程。每次循环都会调用shouldYield判断当前是否有剩余时间

/** @noinline */
function workLoopConcurrent() {
  // Perform work until Scheduler asks us to yield
  while (workInProgress !== null && !shouldYield()) {
    workInProgress = performUnitOfWork(workInProgress);
  }
}
1
2
3
4
5
6
7

那么React16是如何解决中断更新时DOM渲染不完全的问题呢? 在React16中,Reconciler与Renderer不再是交替工作。 当Scheduler将任务交给Reconciler后,Reconciler会为变化的虚拟DOM打上代表增/删/更新的标记,类似这样:

export const Placement = /*             */ 0b0000000000010;
export const Update = /*                */ 0b0000000000100;
export const PlacementAndUpdate = /*    */ 0b0000000000110;
export const Deletion = /*              */ 0b0000000001000;
1
2
3
4

全部标记见这里 (opens new window)

整个Scheduler与Reconciler的工作都在内存中进行。只有当所有组件都完成Reconciler的工作,才会统一交给Renderer。 这里 (opens new window)是React官方对React1新Reconciler的解释 可看到,Reconciler内部采用了Fiber架构

# Renderer(渲染器)

Renderer根据Reconciler为虚拟DOM打的标记,同步执行对应的DOM操作。 之前的Demo在React16架构中整个更新流程为: 其中红框中的步骤随时可能由于以下原因被中断:

  • 有其他更高优任务需先更新
  • 当前帧无剩余时间

由于红框中的工作在内存中进行,不会更新页面上的DOM,所以即使反复中断,用户也看不到更新不完全的DOM。

由于Scheduler和Reconciler都是平台无关的,所以React为他们单独发了一个包react-reconciler (opens new window),我们可用这个包自己实现一个ReactDOM, 具体见参考资料 (opens new window)

#前端#React技术揭秘
上次更新: 2022/09/16, 17:10:42
React理念
Fiber

← React理念 Fiber→

最近更新
01
面试官
03-27
02
this&指针&作用域&闭包
03-27
03
前端
03-27
更多文章>
Theme by Vdoing | Copyright © 2019-2025 chst365 | 豫ICP备17031889号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式