2023-12-05 16:09:45 +08:00

93 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 该文件负责整个 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;