关于react.js:React-源码解析系列-React-的-render-阶段一基本流程介绍

2次阅读

共计 2564 个字符,预计需要花费 7 分钟才能阅读完成。

React 的工作流程

React 的工作流程次要分为 render 和 commit 两个阶段:

  • render 阶段依据 JSX 转化成的 ReactElement(更精确地来说,jsx 经 babel 转化后是 React.createElement() 的代码段,在 render 阶段该代码段被执行后便生成了对应的 ReactElement 对象)来创立 Fiber 树;React 采纳“双缓存”的思维,因而同一时刻维持有两棵 Fiber 树,一颗是 current,对应浏览器以后已渲染的 DOM 树,而另一棵则是 workInProgress,是在初始化时或者组件状态更新后由 reconciler 创立的一个工作正本。
  • commit 阶段指的是把 workInProgress 渲染到页面上,当然这个过程并不会是全量更新,而是依据创立 workInProgress 时打的一些“标记”(effectTag),来确定在某个 DOM 节点上具体做什么操作,比方更新文本、删除节点等,以尽量小的代价来在 DOM 上还原 workInProgress;workInProgress 会在 commit 后被置为 current。

render 阶段的入口

render 阶段开始于 performSyncWorkOnRoot 或 performConcurrentWorkOnRoot 办法的调用,这两个办法的差别在于一个是同步,而另一个是异步 (concurrent) 的。

这两个办法别离会调用上面两个办法—— workLoopSync 和 workLoopConcurrent:

function workLoopSync() {
  // Already timed out, so perform work without checking if we need to yield.
  while (workInProgress !== null) {performUnitOfWork(workInProgress);
  }
}

function workLoopConcurrent() {
  // Perform work until Scheduler asks us to yield
  while (workInProgress !== null && !shouldYield()) {performUnitOfWork(workInProgress);
  }
}

这两个办法的差异在于是否调用 shouldYield() 来判断以后浏览器帧有没有空余工夫,对于 concurrent 模式来说,如果没有空余工夫就会退出以后循环了;能够看到这两个办法最终都调用了 performUnitOfWork

通过办法中的 while 循环,Fiber Reconciler 将实现对虚构 DOM 的一个深度遍历,以及实现对整棵 workInProgress Fiber Tree 的创立。

performUnitOfWork

performUnitOfWork 办法会创立下一个 Fiber 节点,并将其与 workInProgress 所指向的 FiberNode 进行连贯(workInProgress 相当于是以后 FiberTree 上最末的一个 FiberNode,与其相连则示意将新的 FiberNode 挂在 FiberTree 上),实现后将 workInProgress 这 FiberTree 的指针赋值为刚创立的 FiberNode,再进行下一轮的循环。

Fiber Reconciler 因为是从 Stack Reconciler 重构来的,它实际上模仿了“递归”的执行过程,这实际上也是一个相似于“深度优先遍历”的过程。

render 的“递”阶段 —— beginWork

在“递”阶段,调用的是 beginWork 办法,在该办法中会判断以后传入的 Fiber 节点是否有对应的子节点;如果有子节点的话 就创立子 Fiber 节点并返回,这样在 performUnitOfWork 下一轮的循环中就会继续执行子节点的“递”阶段,否则就执行以后 Fiber 节点的“归”阶段。

render 的“归”阶段 —— completeWork

在“归”阶段,调用的是 completeUnitOfWork 办法;在解决完以后节点(次要是创立以后节点的 DOM,以及收拢后辈节点的 DOM 以及 effectTag)后,该办法会判断以后传入的 Fiber 节点是否有对应的兄弟节点(sibling);如果有兄弟节点的话,则返回兄弟节点,下次循环时将进入兄弟节点的“递”阶段,否则就返回父节点,下次循环时执行父节点的“归”阶段。

const siblingFiber = completedWork.sibling;
if (siblingFiber !== null) {
    // If there is more work to do in this returnFiber, do that next.
    workInProgress = siblingFiber;
    return;
}
// Otherwise, return to the parent
completedWork = returnFiber;
// Update the next thing we're working on in case something throws.
workInProgress = completedWork;

举例说明递归的过程

function App() {
    return (
        <p>
            <span>array</span>
            <span>huang</span>
        </p>
    )
}

ReactDom.render(<App />, document.getElementById('#root'));

1. rootFiber beginWork 
2. App Fiber beginWork 
3. p Fiber beginWork 
4. span Fiber beginWork 
5. span Fiber completeWork // 留神这里是间接走到 span 的“归”阶段,因为文本节点 "array" 被优化解决了
6. span Fiber beginWork 
7. span Fiber completeWork
8. p Fiber completeWork 
9. App Fiber completeWork 
10. rootFiber completeWork

流程结尾

至此,render 阶段全副工作实现。在 performSyncWorkOnRoot 函数中 fiberRootNode 被传递给 commitRoot 办法,开启 commit 阶段工作流程。

正文完
 0