原文链接: react fiber 遍历方式简单实现
上一篇: 递归生成平衡二叉树
下一篇: fiber 遍历方式比较
树的遍历方式可以采用递归或者栈模拟递归, 或者队列进行层次遍历
fiber使用链表的方式模拟前序遍历, 在一个循环中完成遍历, 相比如前面几种栈和递归在树的层次比较高的时候调用栈很长, 层次遍历队列的长度也和层级中节点个数的相关, fiber方式调用栈少, 且每次只需要关心当前节点, 在速度和实现上也会有不少优势(速度上大概测出了一倍多)
遍历过程
速度对比, 基本上快一倍, 即使是节点数目较少的情况下
算法思路
1, 获取根dom节点, 以此节点建树, 采用两种方式遍历, 对比遍历结果, dfs实现的前序遍历和fiber的遍历路线应该是一致的
2, fiber节点属性以及遍历路线(这个return简直了... 叫parent不香吗.....)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<style>
.box {
min-height: 50px;
margin: 10px;
border: 4px solid black;
display: flex;
min-width: 50px;
max-width: fit-content;
}
</style>
</head>
<body>
<div id="root" class="box">
a
<div class="box">
b
<div class="box">d</div>
<div class="box">e</div>
</div>
<div class="box">
c
<div class="box">d1</div>
<div class="box">e1
<div class="box">d2</div>
<div class="box">e2</div>
</div>
</div>
</div>
</body>
<script>
function getTree(dom) {
let root = {
id: dom.innerText.split('\n')[0],
dom: dom,
children: []
}
for (let i of [...dom.children]) {
root.children.push(getTree(i))
}
return root
}
function showTree(root) {
if (!root) return
console.log(root.id)
for (let i of root.children)
showTree(i)
}
let div = document.getElementById('root')
let tree = getTree(div)
console.log(tree)
showTree(tree)
// 将tree转化为fabric
function getFiber(dom) {
let root = {
id: dom.innerText.split('\n')[0],
dom: dom,
sibling: null,
return: null,
children: [],
}
let nodes = [...dom.children]
let preNode = null
for (let i = 0; i < nodes.length; i++) {
let node = getFiber(nodes[i])
node.return = root
if (i === nodes.length - 1) {
node.sibling = null
preNode.sibling = node
}
preNode && (preNode.sibling = node)
preNode = node
root.children.push(node)
}
return root
}
function doWork(node) {
return new Promise(resolve => {
node.dom.style = 'border:4px solid red'
setTimeout(
() => {
console.log(node.id)
node.dom.style = 'border:4px solid black'
resolve(node)
}
, 1000
)
})
}
async function showFiber(root) {
let current = root
while (true) {
// console.log(current.id)
await doWork(current)
if (current.children.length) {
current = current.children[0]
continue
}
if (current === root) {
console.log('end')
break
}
while (!current.sibling) {
// console.log(current)
// 如果我们回到了根节点,退出函数
if (!current.return || current.return === root) {
console.log('===')
return;
}
// 设置父节点为当前活跃节点
current = current.return;
}
current = current.sibling
}
}
let fiber = getFiber(div)
console.log(fiber)
showFiber(fiber)
</script>
</html>