React内部怎样遍历Fiber树的呢?
Fiber树结构
在React内部的Fiber节点,主要有以下几个属性:
child: 指向当前节点的子节点sibling: 指向当前节点的兄弟节点return: 指向当前节点的父节点
如上图的一个Fiber Tree,树结构内部依靠child、sibling以及return节点进行连接。那么怎么进行遍历呢?
在react内部是使用深度优先的遍历方式,先从根节点依次向下走到最低层,然后找到最底层的兄弟节点,又依次向下走到最底层,按照这样的方式依次遍历完成整个数组。
我们可以将react中的遍历思想写成一个简单版本:
let nextNode = node1;
function begin() {
while(nextNode) {
console.log('begin', nextNode.val);
if(nextNode.child) {
nextNode = nextNode.child;
} else {
complete()
}
}
}
function complete() {
while(nextNode) {
console.log('complete', nextNode.val);
if(nextNode.sibling) {
nextNode = nextNode.sibling;
return;
}
nextNode = nextNode.return;
}
}
begin()
将上面代码的执行过程图像化如下,分步进行执行过程分析:

- 第一步,将开始节点
node1赋值给全局变量nextNode,执行begin函数,打印begin 1,判断nextNode.child存在,赋值给nextNode,此时nextNode === node2 - 第二步,由于
nextNode存在,继续执行while循环,打印begin 2,判断nextNode.child存在,赋值给nextNode,此时nextNode === node3 - 第三步,由于
nextNode存在,继续执行while循环,打印begin 3,此时nextNode === node3,判断nexNode.child不存在,进入complete函数,执行while循环,打印complete 3 - 第四步,,判断
nextNode.sibling存在,赋值给nextNode,此时nextNode === node4,并执行return,返回到begin()函数中,继续在begin()函数中执行while循环,打印begin 4 - 第五步,此时
nextNode === node4,判断nextNode.child是否存在,赋值给nextNode,此时nextNode === node6,再次进入begin()函数中的while循坏,打印begin 6 - 第六步,此时
nextNode === node6,判断nextNode.child是否存在,不存在,进入complete函数,进入complete中的while循环,打印complete 6 - 第七步,,判断
nextNode.sibling存在,赋值给nextNode,此时nextNode === node7,并执行return,返回到begin()函数中,继续在begin()函数中执行while循环,打印begin 7 - 第八步,此时
nextNode === node7,判断nextNode.child是否存在,赋值给nextNode,此时nextNode === node8,再次进入begin()函数中的while循坏,打印begin 8 - 第九步,此时
nextNode === node8,判断nextNode.child是否存在,不存在,进入complete函数,进入complete中的while循环,打印complete 8 - 第十步,,判断
nextNode.sibling存在,不存在,则将nextNode.return赋值给nextNode,此时nextNode === node7,继续执行complete函数中的while循环,打印complete 7 - 第十一步,判断
nextNode.sibling不存在,继续将nextNode.return赋值给nextNode,此时nextNode === node4,继续执行complete函数中的while循环,打印complete 4 - 第十二步,判断
nextNode.sibling存在,则将其赋值给nextNode,此时nextNode === node5,执行return,返回到begin函数中,进入begin函数中执行while循环,打印begin 5 - 第十三步,判断
nextNode.child不存在,执行complete函数,进入while循环,打印complete 5 - 第十四步,判断
nextNode.sibling不存在,将nextNode.return赋值给nextNode,继续执行while循环,打印complete 2 - 第十五步,判断
nextNode.sibling不存在,将nextNode.return赋值给nextNode,继续执行while循环,打印complete 1
所以上面的代码会打印下面信息:
begin 1
begin 2
begin 3
complete 3
begin 4
begin 6
complete 6
begin 7
begin 8
complete 8
complete 7
complee 4
begin 5
complete 5
complete 2
complete 1
下面是ReactV18中关于Fiber树遍历相关的代码
function commitPassiveMountEffects(root, finishedWork, committedLanes, committedTransitions) {
nextEffect = finishedWork;
commitPassiveMountEffects_begin(finishedWork, root, committedLanes, committedTransitions);
}
function commitPassiveMountEffects_begin(subtreeRoot, root, committedLanes, committedTransitions) {
while (nextEffect !== null) {
var fiber = nextEffect;
var firstChild = fiber.child;
if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {
firstChild.return = fiber;
nextEffect = firstChild;
} else {
commitPassiveMountEffects_complete(subtreeRoot, root, committedLanes, committedTransitions);
}
}
}
function commitPassiveMountEffects_complete(subtreeRoot, root, committedLanes, committedTransitions) {
while (nextEffect !== null) {
var fiber = nextEffect;
if ((fiber.flags & Passive) !== NoFlags) {
setCurrentFiber(fiber);
try {
commitPassiveMountOnFiber(root, fiber, committedLanes, committedTransitions);
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
}
resetCurrentFiber();
}
if (fiber === subtreeRoot) {
nextEffect = null;
return;
}
var sibling = fiber.sibling;
if (sibling !== null) {
sibling.return = fiber.return;
nextEffect = sibling;
return;
}
nextEffect = fiber.return;
}
}
可以看到其核心是一致的。