React双缓存树渲染流程介绍

一、什么是React Fiber

我们都知道从React16.8开始引入了fiber架构。旧版的React的render过程是同步的,如果Render耗时较长,会阻塞页面的其他任务。新版本的Render过程拆分成多个异步任务(纤程),并且是可中断可恢复的,这就是React Fiber.

原理:Render过程主要工作是vdom diff算法找出两棵树的区别,本质上的树的遍历。在旧版本react,假设遍历发生了中断,虽然可以保留当下进行中节点的索引,下次继续时,我们的确可以继续遍历该节点下面的所有子节点,但是没有办法找到其父节点因为每个节点只有其子节点的指向。断点没有办法恢复,只能从头再来一遍。在新的fiber架构中,每个节点有三个指针:分别指向第一个子节点、下一个兄弟节点、父节点。这种数据结构就是fiberNode。

二、React双缓冲树

javascript 复制代码
import React from 'react';
import ReactDom from 'react-dom';

class Home extends React.Component {
  constructor(props) {
     super(props);
     this.state = { step: 0 };
     this.handleClick = this.handleClick.bind(this);
   }
   handleClick() {
     this.setState({step: this.state.step + 1})
    }
  render() {
     const { step } = this.state;
     return (
         <div id={step} onClick={this.handleClick}>
            {step}
         </div>
       )
     }
  }

ReactDom.render(<Home/>, document.getElementById('root'))

渲染流程

  • render阶段 构建workInProgress树,用于本次渲染
  • render结束,commit前 更新容器的finishedWork指针,通知页面渲染
  • commit结束 current树变成alternate树,workInProgress树变成current树,finishedWork树为空

第一次渲染

  • render阶段 初始化工作:创建容器和root fiberNode, current指针指向root fiber
  • 构建workInProgressi树,即将渲染到页面的vdom 除了child、sibling、return:指针,还有alternate它指向备用节点
  • render阶段结束,commit阶段开始 将fiber树容器的finishedWork指针执行workInProgress树root节点
  • commit阶段结束 current指向workInProgree树,finishedWork指向null

第二次渲染

  • render阶段 在current树的基础上构建workInProgress树,current.alternate节点不为空,存在备用节点,直接复用。

current树的其他子节点的alternate都为null,各自创建workInProgress节点

  • render阶段结束,commit阶段开始

    将fiber树容器的finishedWork指针指向workInProgress树root节点

  • commit阶段结束

    current指向workInProgress树,finishedWork指向null

第三次渲染

  • render阶段

    构建workInProgress树,所有fiber节点存在备用节点,直接复用,并将属性复制过去。

  • render阶段结束,commit阶段开始 将fiber树容器的finishedWork指针执行workInProgress树root节点
  • commit阶段结束

    current指向workInProgress树,finishedWork指向null

三、结论

通过上面三次渲染更新过程也可以看出,React在渲染时,会在current树和alternate树之间交替进行,倒来倒去。比如第四次渲染时,第二次渲染完成的alternate树又变成了current树,而第三次渲染完成的树又变成了alternate树。 那为什么React要复用备用的节点,而不是新创建一个呢?最大的原因是节省内存开销,通过复用引旧的备用节点,React不需要额外申请内存空间,在复用时可以直接将current fiber的属性复制到l旧的备用节点。

相关推荐
热爱编程的小曾25 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin37 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox1 小时前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞2 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行2 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_593758102 小时前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox