React Fiber架构

501 阅读4分钟

React15 架构缺点

React16之前的版本比对更新虚拟DOM的过程是采用循环递归方式来实现的,这种比对方式有一个问题,就是一旦任务开始进行就无法中断,如果应用中数组数量庞大,主线程被长期占用,直到整颗虚拟DOM树比对更新完成之后主线程才被释放,主线程才能执行其他任务,这就会导致一些用户交互或动画等任务无法立即得到执行,页面就会产生卡顿,非常的影响用户体验

主要原因就是递归无法中断,执行重的任务耗时较长,javascript又是单线程的,无法同时执行其他任务,导致任务延迟页面卡顿用户体验差。

React15架构可以分为两层:

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

image-20230523143337693.png


每当有更新发生时,Reconciler会做如下工作:

  1. 调用函数组件、或class组件的render方法,将返回的JSX转化为虚拟DOM
  2. 将虚拟DOM和上次更新时的虚拟DOM对比
  3. 通过对比找出本次更新中变化的虚拟DOM
  4. 通知Renderer将变化的虚拟DOM渲染到页面上

而React15使用的是栈调和器,由于递归执行,所以更新一旦开始,中途就无法中断。当调用层级很深时,递归更新时间超过了屏幕刷新时间间隔,用户交互就会卡顿。

react 16架构

React16架构可以分为三层:

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

image.png

相比React15,16增加了一个Scheduler(调度器)

并发&调度(Concurrency & Scheduler)

  • Concurrency 并发: 有能力优先处理更高优事务,同时对正在执行的中途任务可暂存,待高优完成后,再去执行。
  • Scheduler 协调调度: 在浏览器每一帧的时间中,预留一些时间给JS线程,React利用这部分时间更新组件,当预留的时间不够用时,React将线程控制权交还给浏览器使其有时间渲染UI,React则等待下一帧时间到来,继续被中断的工作。

image.png 在源码中,预留的初始时间是5ms

考虑到可中断渲染,并可重回构造。React自行实现了一套体系叫做 React fiber 架构。

Scheduler 运行核心点

  1. 有个任务队列 queue,该队列存放可中断的任务

  2. workLoop对队列里取第一个任务currentTask,进入循环开始执行。

    • 当该任务没有时间 或 需要中断 (渲染任务 或 其他高优任务插入等),则让出主线程。
  3. requestAnimationFrame 计算一帧的空余时间;

  4. 使用new MessageChannel () 执行宏任务;

Fiber架构

界面通过 vdom 描述,但是不是直接手写 vdom,而是 jsx 编译产生的 render function 之后以后生成的。这样就可以加上 stateprops 和一些动态逻辑,动态产生 vdom

vdom 生成之后不再是直接渲染,而是先转成 fiber,这个 vdomfiber 的过程叫做 reconcile

fiber 是一个链表结构,可以打断,这样就可以通过 requestIdleCallback 来空闲调度 reconcile,这样不断的循环,直到处理完所有的 vdomfiberreconcile,就开始 commit,也就是更新到 dom

reconcile 的过程会提前创建好 dom,还会标记出增删改,那么 commit 阶段就很快了。

从之前递归渲染时做 diff 来确定增删改以及创建 dom,提前到了可打断的 reconcile 阶段,让 commit 变得非常快,这就是 fiber 架构的目的和意义。

Fiber的数据结构有三层信息: (采用链表结构

  1. 实例属性

    • 该Fiber的基本信息,例如组件类型等。
  2. 构建属性

    • 构建属性 (returnchildsibling)
  3. 工作属性

    • 数据的变更会导致UI层的变更
    • 为了减少对DOM的直接操作,通过Reconcile进行diff查找,并将需要变更节点,打上标签,变更路径保留在effectList
    • 待变更内容要有Scheduler优先级处理
    • 涉及到diff等查找操作,是需要有个高效手段来处理前后变化,即双缓存机制

链表结构即可支持随时随时中断的诉求

schedule 就是通过空闲调度每个 fiber节点的reconcilevdomfiber),全部 reconcile完了就执行commit\

React Fiber 核心: 自行实现 虚拟栈帧。

总结

React16 使用的是全新的"Fiber调和器",这就依托于React16的重点了—Fiber架构。目前简要概括就是,React16能够实现中断调和,分批次异步地调和。从而达到不因为JS执行时间过久影响浏览器渲染。