React 源码解析系列 - React 的 render 阶段(一)(基本流程介绍)
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。
这两个方法分别会调用下面两个方法—— 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 (array
huang
)
}ReactDom.render(, 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
流程结尾 【React 源码解析系列 - React 的 render 阶段(一)(基本流程介绍)】至此, render 阶段全部工作完成。在 performSyncWorkOnRoot 函数中 fiberRootNode 被传递给 commitRoot 方法,开启 commit 阶段工作流程。
推荐阅读
- Android事件传递源码分析
- react|react 安装
- Quartz|Quartz 源码解析(四) —— QuartzScheduler和Listener事件监听
- Java内存泄漏分析系列之二(jstack生成的Thread|Java内存泄漏分析系列之二:jstack生成的Thread Dump日志结构解析)
- [源码解析]|[源码解析] NVIDIA HugeCTR,GPU版本参数服务器---(3)
- ffmpeg源码分析01(结构体)
- Android系统启动之init.rc文件解析过程
- Java程序员阅读源码的小技巧,原来大牛都是这样读的,赶紧看看!
- 小程序有哪些低成本获客手段——案例解析
- Vue源码分析—响应式原理(二)