React Fiberデータ構造の解明

3392 ワード

このチャプタは、2つの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 = () => [] }
Stock ReconcilerReact 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 b3Fiber ReconcilerReact 16において、ノード間の関係は、データ構造の で表されてもよい.
ノード間のチェーンは次のような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の強み
    上記2つのデータ構造のコードを解析することにより、以下の結論が得られる.
  • は、ツリーの深さ巡回に基づいて実現されるReconciler:一旦呼び出しスタックに入ると、停止できなくなる.
  • は、チェーンに基づいて実現されたReconciler:while(true) {}のループにおいて、currentNodeの割当値によって操作が必要なノードを再取得することができ、割り当て前に他のロジックを実行することができ、これもrequestIdleCallbackFiber Reconcilerで動作できる理由である.
  • 関連リンク
  • The how and why on React’s usage of linked list in Fiber to walk the component's tree