likes
comments
collection
share

自己造React系列——引入可中断fiber,却导致页面展示不完整?

作者站长头像
站长
· 阅读数 16

写在前面

经过上一步的Fiber树结构的改造,我们实现了一边遍历element,一边添加到父级dom上,同时浏览器可以根据需要在每一个节点之后中断渲染,有效解决了页面卡顿问题。但同时带来了另一个问题,因为渲染可以被中断,那么用户看到的页面展示可能就是不完整的,这可怎么办?

自己造React系列——引入可中断fiber,却导致页面展示不完整?

正文

其实我们可以把修改真实dom的操作抽离出来,放在一颗fiberwipRoot上,方便追踪,然后通过commitRoot统一修改真实dom,这样用户就不会看到不完整的页面了。

function commitRoot() {
    // TODO add nodes to dom
}

let nextUnitOfWork = null
let wipRoot = null

function render(element, container) {
    wipRoot = {
        dom: container,
        props: {
            children: [element],
        },
    }
    nextUnitOfWork = wipRoot
}

function workLoop(deadline) {

    let shouldYield = false
    while (nextUnitOfWork && !shouldYield) {
        nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
        shouldYield = deadline.timeRemaining() < 1
    }

    if (!nextUnitOfWork && wipRoot) {
        commitRoot()
    }
    requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)

接下来,我们来看commitRoot具体怎么实现?


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这个最终修改真实dom的方法里,我们递归地向父组件添加添加dom节点。

写在后面

在实际开发过程中,解决问题时经常会遇到解决一个问题,又产生一个新的问题的情况:比如为了解决dom渲染导致页面卡顿的问题,引入了fiber树结构;在解决了卡顿问题的同时,可中断又导致用户看到不完整的页面,这种常见且尴尬的情况。

自己造React系列——引入可中断fiber,却导致页面展示不完整?

这时就要分析新产生的问题的解决方案,以及解决方案可能带来的新问题

  • 如果最后产生不可避免不能接受的新问题就要调整初始问题的解决方案;
  • 当然理想的情况是,解决方案不产生新问题、产生的新问题可以被解决、相比较初始问题而言能被接受