前言
上次我们讲了fiber,我来提一个问题,大家来回顾一下,fiber为什么采用的链式结构?也就是说链式结构有什么特点?
- 可以被中断
- 链式结构方便增加和删除
记住这些特点,所以上一课讲的performUnitOfWork函数其实也就是根据条件生成链式结构树,并返回下一个节点
render和Commit阶段
我们还有另一个问题在这里。
if (fiber.parent) {
fiber.parent.dom.appendChild(fiber.dom)
}
每次处理一个元素时,我们都要向 DOM 添加一个新节点。还有,请记住,浏览器可能会在我们完成渲染整棵树之前中断我们的工作。在这种情况下,用户将看到一个不完整的 UI。我们不想那样。
所以我们需要从这里移除改变DOM的这部分。
替代方案是, 我们将继续保持fiber 树的根节点的追踪。我们称它为正在进行的工作root 或者 wipRoot。
function render(element, container) {
wipRoot = {
dom: container,
props: {
children: [element],
},
};
nextUnitOfWork = wipRoot;
}
这样我们就能一次完成所有的工作(我们知道这是因为没有下一个工作单元了)我们commit这整个fiber tree到这个DOM
function commitRoot() {
// TODO add nodes to dom
}
function workLoop(deadline) {
let shouldYield = false
while (nextUnitOfWork && !shouldYield) {
nextUnitOfWork = performUnitOfWork(
nextUnitOfWork
)
shouldYield = deadline.timeRemaining() < 1
}
if (!nextUnitOfWork && wipRoot) {
commitRoot()
}
requestIdleCallback(workLoop)
}
我们在commitRoot函数中执行它。 这里我们递归的添加所有的node到DOM上
function commitRoot() {
commitWork(wipRoot.child)
wipRoot = null
}
function commitWork(fiber) {
if (!fiber) {
return
}
const domParent = fiber.parent.dom
domParent.appendChild(fiber.dom)
commitWork(fiber.child)
commitWork(fiber.sibling)
}
这里的commitRoot函数,你看这不就是采用的遍历树的算法么,所以学好算法很重要,如果你想成为一代大师的话