介绍
**主要文件
ReactFiberWorkLoop.js
ReactFiberCompleteWork.js
当 React 应用启动时,beginWork 是 React Fiber 架构中的一个重要函数。它的作用是构建 Fiber 树。Fiber 树是一个轻量级的树形结构,它用于描述组件的层级关系以及每个组件的状态。
在 beginWork 函数内部,React 会根据当前 Fiber 对应的组件类型,选择不同的更新函数进行处理。比如,对于函数组件,React 会调用 updateFunctionComponent 函数进行处理;对于类组件,React 会调用 updateClassComponent 函数进行处理。
beginWork 函数会返回一个新的 Fiber 对象,这个 Fiber 对象代表了当前组件的下一个子组件。如果当前组件没有子组件,那么 beginWork 函数会返回 null。
在 beginWork 函数执行完毕之后,React 会将返回的新的 Fiber 对象连接到当前 Fiber 对象的 child 属性上,这样就完成了 Fiber 树的构建。
主要文件:
ReactFiberWorkLoop.js(包含beginWork函数)ReactFiberCompleteWork.js(包含completeWork函数)
ReactFiberWorkLoop.js 文件是 React Fiber 架构中的一个重要文件,它包含了一系列与 Fiber 树构建相关的函数,其中就包括了 beginWork 函数。
ReactFiberCompleteWork.js 文件也是 React Fiber 架构中的一个重要文件,它包含了 completeWork 函数。在构建 Fiber 树的过程中,当一个 Fiber 节点的所有子节点都构建完成后,就会调用 completeWork 函数,执行该 Fiber 节点的完成工作。完成工作包括:创建真实的 DOM 节点、更新组件状态等。
1. BeginWork方法
function scheduleUpdateOnFiber(root, fiber, lane, eventTime) {
markRootUpdated(root u, lane);
//确保调度执行root上的更新
ensureRootIsScheduled(root, eventTime);
}
function ensureRootIsScheduled(root, currentTime) {
// 获取根上的任务,将已经过期的标记为过期,
// 获取当前优先级最高的任务,并获取优先级,和根上在执行的任务对比优先级,/如果新的优先级和老的优先级一样,则可以进行批量更新
// 如果没有要执行的任务,返回
/**
* 省略部分代码
* */
// 在这里调度执行callback,浏览器去执行performConcurrentWorkOnRoot方法更新,返回新的newCallbackNode
newCallbackNode = Scheduler_scheduleCallback(
schedulerPriorityLevel,
performConcurrentWorkOnRoot.bind(null, root) //performConcurrentWorkOnRoot方法为beginWork后面继续这部分
);
}
function performConcurrentWorkOnRoot(root, didTimeout) {
// 1.处理effect里返回的callback
const didFlushPassiveEffects = flushPassiveEffects();
//2 先获取当前根节点上的任务
const originalCallbackNode = root.callbackNode;
//获取当前优先级最高的车道,存储下一条车道
const lanes = getNextLanes(root, NoLanes);
if (lanes === NoLanes) {
return null;
}
// 这里判断是否走时间切片
//某些情况下禁用 time-slicing: 如果不包含阻塞的车道,并且没有超时,就可以并行渲染,就是启用时间分片
//所以说默认更新车道是同步的,不能启用时间分片
//是否不包含阻塞车道
const nonIncludesBlockingLane = !includesBlockingLane(root, lanes);
//是否不包含过期的车道
const nonIncludesExpiredLane = !includesExpiredLane(root, lanes);
//时间片没有过期
const nonTimeout = !didTimeout;
//三个变量都是true,才能进行时间分片,也就是进行并发渲染,也就是可以中断执行
const shouldTimeSlice =
nonIncludesBlockingLane && nonIncludesExpiredLane && nonTimeout;
//执行渲染,得到退出的状态.renderRootConcurrent并发渲染,renderRootSync同步渲染
const exitStatus = shouldTimeSlice
? renderRootConcurrent(root, lanes)
: renderRootSync(root, lanes);
//如果不是渲染中的话,那说明肯定渲染完了
if (exitStatus !== RootInProgress) {
const finishedWork = root.current.alternate;
root.finishedWork = finishedWork;
commitRoot(root); //finishConcurrentRender
}
//说明任务没有完成
if (root.callbackNode === originalCallbackNode) {
//把此函数返回,递归执行
return performConcurrentWorkOnRoot.bind(null, root);
}
return null;
}
function renderRootConcurrent(root, lanes) {
//因为在构建fiber树的过程中,此方法会反复进入,会进入多次
//只有在第一次进来的时候会创建新的fiber树,或者说新fiber
if (workInProgressRoot !== root || workInProgressRootRenderLanes !== lanes) {
prepareFreshStack(root, lanes);
}
//在当前分配的时间片(5ms)内执行fiber树的构建或者说渲染,
workLoopConcurrent();
//如果 workInProgress不为null,说明fiber树的构建还没有完成
if (workInProgress !== null) {
return RootInProgress;
}
//如果workInProgress是null了说明渲染工作完全结束了
return workInProgressRootExitStatus;
}
function workLoopConcurrent() {
// Perform work until Scheduler asks us to yield
while (workInProgress !== null && !shouldYield()) {
// $FlowFixMe[incompatible-call] found when upgrading Flow
performUnitOfWork(workInProgress);
}
}
function performUnitOfWork(unitOfWork) {
//获取新的fiber对应的老fiber
const current = unitOfWork.alternate;
//完成当前fiber的子fiber链表构建后
const next = beginWork(current, unitOfWork, workInProgressRootRenderLanes);
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
//如果没有子节点表示当前的fiber已经完成了
completeUnitOfWork(unitOfWork);
} else {
//如果有子节点,就让子节点成为下一个工作单元
workInProgress = next;
}
}
function beginWork(current, workInProgress, renderLanes) {
//在构建fiber树之后清空lanes
//在进入开始阶段之前,请清除挂起的更新优先级。
//这里根据tag判断去实现函数组件或者类组件或者其他方法,这里只是罗列了几种,总共二十多种
// updateHostText updateMemoComponent updateSuspenseComponent updatePortalComponent updateFragment updateProfiler mountIncompleteClassComponent
workInProgress.lanes = 0;
switch (workInProgress.tag) {
// 因为在React里组件其实有两种,一种是函数组件,一种是类组件,但是它们都是都是函数
case IndeterminateComponent:
return mountIndeterminateComponent(
current,
workInProgress,
workInProgress.type,
renderLanes
);
case FunctionComponent: {
const Component = workInProgress.type;
const nextProps = workInProgress.pendingProps;
return updateFunctionComponent(
current,
workInProgress,
Component,
nextProps,
renderLanes
);
}
case ClassComponent: {
const Component = workInProgress.type;
const unresolvedProps = workInProgress.pendingProps;
const resolvedProps =
workInProgress.elementType === Component
? unresolvedProps
: resolveDefaultProps(Component, unresolvedProps);
return updateClassComponent(
current,
workInProgress,
Component,
resolvedProps,
renderLanes
);
}
case HostRoot:
return updateHostRoot(current, workInProgress, renderLanes);
case HostComponent:
return updateHostComponent(current, workInProgress, renderLanes);
case HostText:
return null;
default:
return null;
}
}
function completeUnitOfWork(unitOfWork) {
let completedWork = unitOfWork;
do {
const current = completedWork.alternate;
const returnFiber = completedWork.return;
//执行此fiber 的完成工作,如果是原生组件的话就是创建真实的DOM节点
completeWork(current, completedWork);
//如果有弟弟,就构建弟弟对应的fiber子链表
const siblingFiber = completedWork.sibling;
if (siblingFiber !== null) {
workInProgress = siblingFiber;
return;
}
//如果没有弟弟,说明这当前完成的就是父fiber的最后一个节点
//也就是说一个父fiber,所有的子fiber全部完成了
completedWork = returnFiber;
workInProgress = completedWork;
} while (completedWork !== null);
//如果走到了这里,说明整个fiber树全部构建完毕,把构建状态设置为空成
if (workInProgressRootExitStatus === RootInProgress) {
workInProgressRootExitStatus = RootCompleted;
}
}
2.completeWork方法
function completeWork(current, workInProgress) {
const newProps = workInProgress.pendingProps;
switch (workInProgress.tag) {
case HostRoot:
bubbleProperties(workInProgress);
break;
case FunctionComponent:
bubbleProperties(workInProgress);
break;
case HostText:
//如果完成的fiber是文本节点,那就创建真实的文本节点
const newText = newProps;
//创建真实的DOM节点并传入stateNode
workInProgress.stateNode = createTextInstance(newText);
//向上冒泡属性
bubbleProperties(workInProgress);
break;
}
}
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第6天,点击查看活动详情