title |
---|
两大工作循环 |
在前文(React 应用的宏观包结构)中, 介绍了react
核心包之间的依赖和调用关系, 并绘制出了概览图. 在概览图中, 可以看到有两个大的循环, 它们分别位于scheduler
和react-reconciler
包中:
本文将这两个循环分别表述为任务调度循环
和fiber构造循环
. 接下来从宏观角度阐述这两大循环的作用, 以及它们之间的区别和联系. 更深入的源码分析分别在scheduler 调度机制
和fiber 树构造
章节中详细解读.
任务调度循环
源码位于Scheduler.js
, 它是react
应用得以运行的保证, 它需要循环调用, 控制所有任务(task
)的调度.
fiber构造循环
源码位于ReactFiberWorkLoop.js
, 控制 fiber 树的构造, 整个过程是一个深度优先遍历.
这两个循环对应的 js 源码不同于其他闭包(运行时就是闭包), 其中定义的全局变量, 不仅是该作用域的私有变量, 更用于控制react应用的执行过程
.
-
区别
任务调度循环
是以二叉堆
为数据结构(详见react 算法之堆排序), 循环执行堆
的顶点, 直到堆
被清空.任务调度循环
的逻辑偏向宏观, 它调度的是每一个任务(task
), 而不关心这个任务具体是干什么的(甚至可以将Scheduler
包脱离react
使用), 具体任务其实就是执行回调函数performSyncWorkOnRoot
或performConcurrentWorkOnRoot
.fiber构造循环
是以树
为数据结构, 从上至下执行深度优先遍历(详见react 算法之深度优先遍历).fiber构造循环
的逻辑偏向具体实现, 它只是任务(task
)的一部分(如performSyncWorkOnRoot
包括:fiber
树的构造,DOM
渲染, 调度检测), 只负责fiber
树的构造.
-
联系
fiber构造循环
是任务调度循环
中的任务(task
)的一部分. 它们是从属关系, 每个任务都会重新构造一个fiber
树.
通过上文的描述, 两大循环的分工可以总结为: 大循环(任务调度循环)负责调度task
, 小循环(fiber 构造循环)负责实现task
.
react 运行的主干逻辑, 即将输入转换为输出
的核心步骤, 实际上就是围绕这两大工作循环进行展开.
结合上文的宏观概览图(展示核心包之间的调用关系), 可以将 react 运行的主干逻辑进行概括:
- 输入: 将每一次更新(如: 新增, 删除, 修改节点之后)视为一次
更新需求
(目的是要更新DOM
节点). - 注册调度任务:
react-reconciler
收到更新需求
之后, 并不会立即构造fiber树
, 而是去调度中心scheduler
注册一个新任务task
, 即把更新需求
转换成一个task
. - 执行调度任务(输出): 调度中心
scheduler
通过任务调度循环
来执行task
(task
的执行过程又回到了react-reconciler
包中).fiber构造循环
是task
的实现环节之一, 循环完成之后会构造出最新的 fiber 树.commitRoot
是task
的实现环节之二, 把最新的 fiber 树最终渲染到页面上,task
完成.
主干逻辑就是输入到输出
这一条链路, 为了更好的性能(如批量更新
, 可中断渲染
等功能), react
在输入到输出的链路上做了很多优化策略, 比如本文讲述的任务调度循环
和fiber构造循环
相互配合就可以实现可中断渲染
.
本节从宏观角度描述了react
源码中的两大工作循环. 通过这两个大循环概括出react
运行的主干逻辑. react-reconciler
和Scheduler
包代码量多且逻辑复杂, 但实际上大部分都是服务于这个主干. 了解这两大循环, 更容易理解react
的整体运行链路.