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 parentcompletedWork = 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 completeWork8. p Fiber completeWork 9. App Fiber completeWork 10. rootFiber completeWork
流程结尾
至此, render 阶段全副工作实现。在 performSyncWorkOnRoot 函数中 fiberRootNode 被传递给 commitRoot 办法,开启 commit 阶段工作流程。