React源码-初始加载beginWork和completeWork

111 阅读5分钟

介绍

**主要文件 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天,点击查看活动详情