此章节会通过两个 demo 来展示 Stack Reconciler 以及 Fiber Reconciler 的数据结构。

个人博客

首先用代码表示上图节点间的关系。比如 a1 节点下有 b1、b2、b3 节点, 就可以把它们间的关系写成 a1.render = () => [b1, b2, b3];

var a1 = { name: 'a1', render = () => [b1, b2, b3] }
var b1 = { name: 'b1', render = () => [c1] }
var b2 = { name: 'b2', render = () => [c2] }
var b3 = { name: 'b3', render = () => [] }
var c1 = { name: 'c1', render = () => [d1] }
var c2 = { name: 'c2', render = () => [] }
var d1 = { name: 'd1', render = () => [d2] }
var d2 = { name: 'd2', render = () => [] }

Stack Reconciler

React 16 之前,节点之间的关系可以用数据结构中树的深度遍历来表示。

如下实现 walk 函数, 将深度遍历的节点打印出来。

walk(a1)function walk(instance) {if (!instance) returnconsole.log(instance.name)instance.render().map(walk)
}

输出结果为: a1 b1 c1 d1 d2 b2 c2 b3

Fiber Reconciler

React 16 中,节点之间的关系可以用数据结构中的链表来表示。

节点之间的链表有三种情形, 用图表示如下:

  1. 父节点到子节点(红色虚线)
  2. 同层节点(黄色虚线)
  3. 子节点到父节点(蓝色虚线)

父节点指向第一个子节点, 每个子节点都指向父节点,同层节点间是单向链表。

首先, 构建节点的数据结构, 如下所示:

var FiberNode = function(instance) {this.instance = instancethis.parent = nullthis.sibling = nullthis.child = null
}

然后创建一个将节点串联起来的 connect 函数:

var connect = function(parent, childList) {parent.child = childList.reduceRight((prev, current) => {const fiberNode = new FiberNode(current)fiberNode.parent = parentfiberNode.sibling = prevreturn fiberNode}, null)return parent.child
}

在 JavaScript 中实现链表的数据结构可以巧用 reduceRight

connect 函数中实现了上述链表关系。可以像这样使用它:

var parent = new FiberNode(a1)
var childFirst = connect(parent, a1.render())

这样子便完成了 a1 节点指向 b1 节点的链表、b1、b2、b3 节点间的单向链表以及 b1、b2、b3 节点指向 a1 节点的链表。

最后剩下 goWalk 函数将全部节点给遍历完。

// 打印日志以及添加列表
var walk = function(node) {console.log(node.instance.name)const childLists = node.instance.render()let child = nullif (childLists.length > 0) {child = connect(node, childLists)}return child
}var goWalk = function(root) {let currentNode = rootwhile (true) {const child = walk(currentNode)// 如果有子节点if (child) {currentNode = childcontinue}// 如果没有相邻节点, 则返回到父节点while (!currentNode.sibling) {currentNode = currentNode.parentif (currentNode === root) {return}}// 相邻节点currentNode = currentNode.sibling}
}// 调用
goWalk(new FiberNode(a1))

打印结果为 a1 b1 c1 d1 d2 b2 c2 b3

Fiber Reconciler 的优势

通过分析上述两种数据结构实现的代码,可以得出下面结论:

  • 基于树的深度遍历实现的 Reconciler: 一旦进入调用栈便无法暂停;
  • 基于链表实现的 Reconciler: 在 while(true) {} 的循环中, 可以通过 currentNode 的赋值重新得到需要操作的节点,而在赋值之前便可以'暂停'来执行其它逻辑, 这也是 requestIdleCallback 能得以在 Fiber Reconciler 的原因。

相关链接

  • The how and why on React’s usage of linked list in Fiber to walk the component’s tree

React Fiber 数据结构揭秘相关推荐

  1. 六个问题让你更懂 React Fiber

    作者 | 零一0101 来源 | 前端印象 React Fiber 是Facebook花费两年余时间对 React 做出的一个重大改变与优化,是对 React 核心算法的一次重新实现.从Faceboo ...

  2. React Fiber 原理介绍

    欢迎关注我的公众号睿Talk,获取我最新的文章: 一.前言 在 React Fiber 架构面世一年多后,最近 React 又发布了最新版 16.8.0,又一激动人心的特性:React Hooks 正 ...

  3. 转载:React Fiber架构(浅显易懂)

    性能优化是一个系统性的工程,如果只看到局部,引入算法,当然是越快越好; 但从整体来看,在关键点引入缓存,可以秒杀N多算法,或另辟蹊径,探索事件的本质,可能用户要的并不是快-- React16启用了全新 ...

  4. React Fiber 了解一下

    旧版React中,更新过程是同步的,这可能会导致性能问题. 当React决定要更新组件树时,会做很多事,比如调用各个组件的生命周期函数,计算和比对Virtual DOM,最后更新DOM树,这整个过程是 ...

  5. 前端工程师的自我修养:React Fiber 是如何实现更新过程可控的

    前言 从 React 16 开始,React 采用了 Fiber 机制替代了原先基于原生执行栈递归遍历 VDOM 的方案,提高了页面渲染性能和用户体验.乍一听 Fiber 好像挺神秘,在原生执行栈都还 ...

  6. 这可能是最通俗的 React Fiber 打开方式

    作者:荒山 https://juejin.im/post/5dadc6045188255a270a0f85 温馨提示:由于 wx 外链限制,文中外链请点击阅读原文查看. 写一篇关于 React Fib ...

  7. React Fiber详解

    问题是什么? 我们先看一个例子: https://claudiopro.github.io/react-fiber-vs-stack-demo/stack.html 在上面这张图片中,页面出现一卡一卡 ...

  8. React Fiber 原理

    持续学习中- 源码版本: v17.0.1, 官方源码地址 源码调试教程 调试的源码 画图软件 浏览器的一帧 浏览器中, 页面都是一帧一帧的绘制出来的, 渲染的帧率和设备的刷新率是一致的, 以常用的显示 ...

  9. React Fiber

    React Fiber是对核心算法的一次重新实现 React Fiber的方式 破解JavaScript中同步操作时间过长的方法其实很简单--分片. 把一个耗时长的任务分成很多小片,每一个小片的运行时 ...

最新文章

  1. 四层和七层交换技术-loadbalance
  2. corosync+pacemaker在centos7上的安装,配置简述
  3. P5303 [GXOI/GZOI2019]逼死强迫症(斐波拉契、矩阵乘法)
  4. JDK1.3安装出现/lib/ld-linux.so.2: bad ELF interpreter: No such file or directory Done.
  5. 用sfc命令修复Windows7的系统文件
  6. dajngo电商数据库设计图,通用版本
  7. 手机怎么用java9_java9_java9官方版 32位64位 最新版_天天下载手机版
  8. 传智播客 C/C++学习笔记 内存四区模型
  9. hp服务器装vm系统,服务器虚拟化ESXi 5.5安装过程(HP)
  10. 【Linux】一步一步学Linux——hostid命令(246)
  11. 不同音乐格式之谜(wav,flac,ape,wv,tak,ogg,aac)
  12. [#32;] 在wordpress [the_excerpt()] 函数执行的妙用
  13. 编辑视频贴纸软件_微剪辑 - 视频编辑神器/专业剪辑软件 贴纸/字幕/音乐
  14. excel统计每个单元格内的单词及空格的个数
  15. 服务器集群可视化监控-Prometheus+Grafana
  16. 【git】统计每个人的代码行数
  17. android usb单反相机,android mtp 获取单反相机中的照片
  18. 快速定量,Abbkine 蛋白质定量试剂盒BCA法来了!
  19. 研究生计算机学院换研究方向不换导师,南邮自杀研究生曾抱怨“导师不让毕业” 导师被停职...
  20. ABAP项目砖家之旅-基础篇

热门文章

  1. Android AOSP 单独编译某一模块
  2. 访客模式(Guest Mode)
  3. cordova入门——cordova环境配置
  4. (0020)iOS 开发之-设计模式-懒加载解惑
  5. postman断言测试脚本二 (对数据格式和内容匹配测试)
  6. node--静态文件托管,路由,模板引擎
  7. webpack 安装卸载
  8. YII2 模型关联之 一对多
  9. #1074 : 字体设计
  10. Spring ContextLoaderListener与DispatcherServlet所加载的applicationContext的区别