此章节会经过两个 demo
来展现 Stack Reconciler
以及 Fiber Reconciler
的数据结构。node
我的博客react
首先用代码表示上图节点间的关系。好比 a1 节点
下有 b一、b二、b3 节点
, 就能够把它们间的关系写成 a1.render = () => [b1, b2, b3]
;git
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 = () => [] }
在 React 16
以前,节点之间的关系能够用数据结构中树的深度遍历
来表示。github
以下实现 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
函数
在 React 16
中,节点之间的关系能够用数据结构中的链表
来表示。this
节点之间的链表有三种情形, 用图表示以下:日志
父节点指向第一个子节点, 每一个子节点都指向父节点,同层节点间是单向链表。code
首先, 构建节点的数据结构, 以下所示:component
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 节点
的链表、b一、b二、b3 节点间
的单向链表以及 b一、b二、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
经过分析上述两种数据结构实现的代码,能够得出下面结论:
while(true) {}
的循环中, 能够经过 currentNode
的赋值从新获得须要操做的节点,而在赋值以前即可以'暂停'来执行其它逻辑, 这也是 requestIdleCallback
能得以在 Fiber Reconciler
的缘由。