此章節會經過兩個 demo
來展現 Stack Reconciler
以及 Fiber Reconciler
的數據結構。node
我的博客
首先用代碼表示上圖節點間的關係。好比 a1 節點
下有 b一、b二、b3 節點
, 就能夠把它們間的關係寫成 a1.render = () => [b1, b2, b3]
;react
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
以前,節點之間的關係能夠用數據結構中樹的深度遍歷
來表示。git
以下實現 walk
函數, 將深度遍歷的節點打印出來。github
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
父節點指向第一個子節點, 每一個子節點都指向父節點,同層節點間是單向鏈表。
首先, 構建節點的數據結構, 以下所示:spa
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
函數中實現了上述鏈表關係。能夠像這樣使用它:code
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
的緣由。