此章节会通过两个 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) return
console.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 = instance
this.parent = null
this.sibling = null
this.child = null
}

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

var connect = function(parent, childList) {
parent.child = childList.reduceRight((prev, current) => {
const fiberNode = new FiberNode(current)
fiberNode.parent = parent
fiberNode.sibling = prev
return 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 = null
if (childLists.length > 0) {
child = connect(node, childLists)
}
return child
} var goWalk = function(root) {
let currentNode = root while (true) {
const child = walk(currentNode)
// 如果有子节点
if (child) {
currentNode = child
continue
} // 如果没有相邻节点, 则返回到父节点
while (!currentNode.sibling) {
currentNode = currentNode.parent
if (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 的原因。

相关链接

React Fiber 数据结构揭秘的更多相关文章

  1. React Fiber源码分析 (介绍)

    写了分析源码的文章后, 总觉得缺少了什么, 在这里补一个整体的总结,输出个人的理解~ 文章的系列标题为Fiber源码分析, 那么什么是Fiber,官方给出的解释是: React Fiber是对核心算法 ...

  2. Omi架构与React Fiber

    原文链接-https://github.com/AlloyTeam/omi/tree/master/tutorial 写在前面 Omi框架在架构设计的时候就决定把update的控制权交给了开发者,视灵 ...

  3. react fiber

    react fiber https://github.com/acdlite/react-fiber-architecture https://github.com/facebook/react/is ...

  4. 瞧一瞧React Fiber

    啥是React Fiber? React Fiber,简单来说就是一个从React v16开始引入的新协调引擎,用来实现Virtual DOM的增量渲染. 说人话:就是一种能让React视图更新过程变 ...

  5. React Fiber源码分析 第二篇(同步模式)

    先附上两张流程图 1.scheduleRootUpdate  这个函数主要执行了两个操作  1个是创建更新createUpdate并放到更新队列enqueueUpdate, 1个是执行sheculeW ...

  6. React Fiber源码分析 第一篇

    先附上流程图一张 先由babel编译, 调用reactDOM.render,入参为element, container, callback, 打印出来可以看到element,container,cal ...

  7. 你真的懂redis的数据结构了吗?redis内部数据结构和外部数据结构揭秘

    Redis有哪些数据结构? 字符串String.字典Hash.列表List.集合Set.有序集合SortedSet. 很多人面试时都遇到过这种场景吧? 其实除了上面的几种常见数据结构,还需要加上数据结 ...

  8. React Fiber源码分析 第三篇(异步状态)

    先附上流程图~ 调用setState时, 会调用classComponentUpdater的enqueueSetState方法, 同时将新的state作为payload参数传进 enqueueSetS ...

  9. redis内部数据结构和外部数据结构揭秘

    Redis有哪些数据结构? 字符串String.字典Hash.列表List.集合Set.有序集合SortedSet. 很多人面试时都遇到过这种场景吧? 其实除了上面的几种常见数据结构,还需要加上数据结 ...

随机推荐

  1. 基础java中的package的命名规则和import的使用

    包的命名一般用公司域名但是注意域名后辍要放前面如下 package com.cnblogs.i.Cat//对应地址是com/cnblos/i/cat.class也就是Cat.class的地址 如果想将 ...

  2. python学习:输入设置

    输入设置 输入用户名和密码 代码: _user = "alex"_password = "abc123" username = input("User ...

  3. ztree设置节点checked,选中某节点等相关操作

    ztree设置节点checked,选中某节点等相关操作 1.根据id获取树的某个节点: var zTree = $.fn.zTree.getZTreeObj("mytree"); ...

  4. asp.net core 下载文件,上传excel文件

    下载文件: 代码: 后端代码: public IActionResult DownloadFile() { var FilePath = @"./files/deparment.xlsx&q ...

  5. js 原生: 身份证脱敏、唯一随机字符串uuid、对于高 index 元素的隐藏与显示

    1. 对于高 index 元素的隐藏 与 显示 export const hideIndexEle = (cssStr)=>{ const player = getElementsByCss(c ...

  6. 2.9 linux学习(1)

    2019-2-9 16:07:44 学一下Linux,多学一点东西 新认识个老师,超哥 很牛逼感觉! https://www.cnblogs.com/pyyu/p/9276851.html 这是入门参 ...

  7. 常用的js效果

    使用jquery实现鼠标悬停显示层 <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...

  8. 认识scrapy

    1.写一个爬虫,需要做很多事情.比如:发送网络请求,数据解析,数据存储,反扒虫虫机制(更换IP代理,设置请求头等),异步请求等.这些工作如果每次都要从零开始写的话,比较浪费时间.因此scrapy吧一些 ...

  9. c# 钩子类

    using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using S ...

  10. Spring Cloud 微服务架构全链路实践

    阅读目录: 1. 网关请求流程 2. Eureka 服务治理 3. Config 配置中心 4. Hystrix 监控 5. 服务调用链路 6. ELK 日志链路 7. 统一格式返回 Java 微服务 ...