93 lines
2.7 KiB
JavaScript
93 lines
2.7 KiB
JavaScript
// 该文件负责整个 React 的一个执行流行
|
||
import beginWork from "./ReactFiberBeginWork";
|
||
import completeWork from "./ReactFiberCompleteWork";
|
||
import commitWorker from "./ReactFiberCommitWork";
|
||
|
||
// wip 的英语全称为 work in progress,表示正在进行的工作
|
||
// 我们使用这个变量来保存当前正在进行的工作 fiber 对象
|
||
let wip = null;
|
||
|
||
// 从名字上也可以看出,这是保存当前根节点的 fiber 对象
|
||
let wipRoot = null;
|
||
|
||
function scheduleUpdateOnFiber(fiber) {
|
||
wip = fiber;
|
||
wipRoot = fiber;
|
||
|
||
// 目前我们先使用 requestIdleCallback 来进行调用
|
||
// 后期使用 scheduler 包来进行调用
|
||
// 当浏览器的每一帧有空闲时间的时候,就会执行 workloop 函数
|
||
requestIdleCallback(workloop);
|
||
}
|
||
|
||
/**
|
||
* 该函数会在每一帧有剩余时间的时候执行
|
||
*/
|
||
function workloop(deadline) {
|
||
while (wip && deadline.timeRemaining() > 0) {
|
||
// 进入此循环,说明有需要进行处理的 fiber 节点
|
||
// 并且目前也有时间来处理
|
||
performUnitOfWork(); // 该方法负责处理一个 fiber 节点
|
||
}
|
||
|
||
// 代码来这里,说明要么是没时间,这个我们不需要管
|
||
// 还有一种情况,就是整个 fiber 树都处理完了
|
||
if (!wip) {
|
||
// 说明整个 fiber 树都处理完了
|
||
// 我们需要将 wipRoot 提交到 DOM 节点上
|
||
commitRoot();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 该函数主要负责处理一个 fiber 节点
|
||
* 有下面的事情要做:
|
||
* 1. 处理当前的 fiber 对象
|
||
* 2. 通过深度优先遍历子节点,生成子节点的 fiber 对象,然后继续处理
|
||
* 3. 提交副作用
|
||
* 4. 进行渲染
|
||
*/
|
||
function performUnitOfWork() {
|
||
beginWork(wip); // 处理当前的 fiber 对象
|
||
|
||
// 如果有子节点,将 wip 更新为子节点
|
||
if (wip.child) {
|
||
wip = wip.child;
|
||
return;
|
||
}
|
||
|
||
completeWork(wip);
|
||
|
||
// 如果没有子节点,就需要找到兄弟节点
|
||
let next = wip; // 先缓存一下当前的 wip
|
||
while (next) {
|
||
if (next.sibling) {
|
||
wip = next.sibling;
|
||
return;
|
||
}
|
||
|
||
// 如果没有进入上面的 if,说明当前节点后面已经没有兄弟节点了
|
||
// 那么就需要将父节点设置为当前正在工作的节点,然后在父亲那一层继续寻找兄弟节点
|
||
next = next.return;
|
||
|
||
// 在寻找父亲那一辈的兄弟节点之前,先执行一下 completeWork 方法
|
||
completeWork(next);
|
||
}
|
||
|
||
// 如果执行到这里,说明整个 fiber 树都处理完了
|
||
// 没有节点需要处理了
|
||
wip = null;
|
||
}
|
||
|
||
/**
|
||
* 执行该方法的时候,说明整个节点的协调工作已经完成
|
||
* 接下来就进入到渲染阶段
|
||
*/
|
||
function commitRoot() {
|
||
commitWorker(wipRoot);
|
||
// 渲染完成后将 wipRoot 置为 null
|
||
wipRoot = null;
|
||
}
|
||
|
||
export default scheduleUpdateOnFiber;
|