React19源码阅读之commitRoot

news2025/4/25 9:26:28

commitRoot入口

在finishConcurrentRender函数,commitRootWhenReady函数,commitRoot函数。

commitRoot流程图

commitRoot函数

commitRoot 函数是 React 渲染流程中用于提交根节点的关键函数。它的主要作用是设置相关的优先级和状态,然后调用 commitRootImpl 函数来实际执行根节点的提交操作,最后在操作完成后恢复之前的状态。

函数参数含义

  1. root: 类型为 FiberRoot,代表 React 应用的根节点,包含了整个应用的渲染信息。
  2. recoverableErrors: 类型为 null | Array<CapturedValue<mixed>>,是一个可恢复错误的数组,用于处理在渲染过程中捕获到的可恢复错误。
  3. transitions: 类型为 Array<Transition> | null,表示渲染过程中涉及的过渡任务数组。
  4. didIncludeRenderPhaseUpdate: 布尔类型,指示渲染阶段是否包含更新操作。
  5. spawnedLane: 类型为 Lane,表示在渲染过程中产生的新的渲染优先级车道。
  6. updatedLanes: 类型为 Lanes,表示在渲染过程中更新的渲染优先级车道。
  7. suspendedRetryLanes: 类型为 Lanes,表示暂停后重试的渲染优先级车道。
  8. suspendedCommitReason: 类型为 SuspendedCommitReason,是一个仅用于性能分析的参数,指示提交操作被暂停的原因。
  9. completedRenderStartTime: 数值类型,是一个仅用于性能分析的参数,记录渲染开始的时间。
  10. completedRenderEndTime: 数值类型,是一个仅用于性能分析的参数,记录渲染结束的时间。
function commitRoot(
  root: FiberRoot,
  recoverableErrors: null | Array<CapturedValue<mixed>>,
  transitions: Array<Transition> | null,
  didIncludeRenderPhaseUpdate: boolean,
  spawnedLane: Lane,
  updatedLanes: Lanes,
  suspendedRetryLanes: Lanes,
  // suspendedCommitReason: SuspendedCommitReason, // Profiling-only
  // completedRenderStartTime: number, // Profiling-only
  // completedRenderEndTime: number, // Profiling-only
) {
  const prevTransition = ReactSharedInternals.T;
  const previousUpdateLanePriority = getCurrentUpdatePriority();
  try {
     // 设置新的更新优先级并清空过渡状态
    setCurrentUpdatePriority(DiscreteEventPriority);
    ReactSharedInternals.T = null;
    
    commitRootImpl(
      root,
      recoverableErrors,
      transitions,
      didIncludeRenderPhaseUpdate,
      previousUpdateLanePriority,
      spawnedLane,
      updatedLanes,
      suspendedRetryLanes,
      suspendedCommitReason,
      completedRenderStartTime,
      completedRenderEndTime,
    );
  } finally {
    // 恢复之前的状态
    ReactSharedInternals.T = prevTransition;
    setCurrentUpdatePriority(previousUpdateLanePriority);
  }
}

commitRootImpl函数

commitRootImpl 函数是 React 渲染流程中用于提交根节点的核心函数,它负责将渲染阶段生成的结果应用到实际的 DOM 上,并执行相关的副作用操作。

  1. 更新 DOM:将 Fiber 树的变化应用到真实的 DOM 上,完成视图的更新。
  2. 执行副作用:处理各种副作用,包括 useEffectuseLayoutEffect 等钩子函数的执行,以及生命周期方法的调用。
  3. 清理和重置状态:在提交完成后,清理和重置相关的状态,为下一次渲染做准备
function commitRootImpl(
  root: FiberRoot,
  recoverableErrors: null | Array<CapturedValue<mixed>>,
  transitions: Array<Transition> | null,
  didIncludeRenderPhaseUpdate: boolean,
  renderPriorityLevel: EventPriority,
  spawnedLane: Lane,
  updatedLanes: Lanes,
  suspendedRetryLanes: Lanes,
  // suspendedCommitReason: SuspendedCommitReason, // Profiling-only
  // completedRenderStartTime: number, // Profiling-only
  // completedRenderEndTime: number, // Profiling-only
) {
  // 循环调用 flushPassiveEffects 函数,直到没有待处理的被动副作用。
  // 被动副作用通常包括 useEffect 钩子函数的执行。
  do {
    flushPassiveEffects();
  } while (rootWithPendingPassiveEffects !== null);


  // 获取已完成的 Fiber 树(finishedWork)和已完成的优先级车道(lanes)。
  const finishedWork = root.finishedWork;
  const lanes = root.finishedLanes;


  // 如果没有已完成的 Fiber 树,则直接返回。
  if (finishedWork === null) {
    return null;
  } 
  // 将 root.finishedWork 和 root.finishedLanes 重置。
  root.finishedWork = null;
  root.finishedLanes = NoLanes;


  // 重置根节点的回调节点、回调优先级和取消待提交的状态。
  root.callbackNode = null;
  root.callbackPriority = NoLane;
  root.cancelPendingCommit = null;


  // 合并 finishedWork 的车道和子车道,得到剩余的优先级车道
  let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);
  // 获取在渲染阶段并发更新的车道。
  const concurrentlyUpdatedLanes = getConcurrentlyUpdatedLanes();


  // 合并车道
  remainingLanes = mergeLanes(remainingLanes, concurrentlyUpdatedLanes);


  // 将 didIncludeCommitPhaseUpdate 标志重置为 false,用于检测提交阶段是否有递归更新。
  didIncludeCommitPhaseUpdate = false;


  // 如果根节点和工作进度根节点一致,则重置相关状态。
  if (root === workInProgressRoot) {
    // We can reset these now that they are finished.
    workInProgressRoot = null;
    workInProgress = null;
    workInProgressRootRenderLanes = NoLanes;
  } 


  // 检查子树是否有 BeforeMutation、Mutation、Layout 或 Passive 副作用。
  const subtreeHasEffects =
    (finishedWork.subtreeFlags &
     (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
    NoFlags;


  // 检查根节点是否有 BeforeMutation、Mutation、Layout 或 Passive 副作用。
  const rootHasEffect =
    (finishedWork.flags &
     (BeforeMutationMask | MutationMask | LayoutMask | PassiveMask)) !==
    NoFlags;


  if (subtreeHasEffects || rootHasEffect) {
    const prevTransition = ReactSharedInternals.T;
    ReactSharedInternals.T = null;
    
    const previousPriority = getCurrentUpdatePriority();
    setCurrentUpdatePriority(DiscreteEventPriority);


    const prevExecutionContext = executionContext;
    executionContext |= CommitContext;


    // Before Mutation 阶段
    const shouldFireAfterActiveInstanceBlur = commitBeforeMutationEffects(
      root,
      finishedWork,
    );
    // Mutation 阶段
    // 执行 commitMutationEffects 函数,将 Fiber 树的变化应用到真实的 DOM 上。
    commitMutationEffects(root, finishedWork, lanes);


    if (enableCreateEventHandleAPI) {
      if (shouldFireAfterActiveInstanceBlur) {
        afterActiveInstanceBlur();
      }
    }
    resetAfterCommit(root.containerInfo);
    root.current = finishedWork;


     // Layout 阶段
    // 执行 commitLayoutEffects 函数,调用 useLayoutEffect 钩子函数和相关的生命周期方法。
    commitLayoutEffects(finishedWork, root, lanes);
    // 请求浏览器进行绘制,更新视图。
    requestPaint();


    // 恢复上下文和优先级
    executionContext = prevExecutionContext;
    setCurrentUpdatePriority(previousPriority);
    ReactSharedInternals.T = prevTransition;
    
  } else {
    // No effects.
    root.current = finishedWork;
  }


  const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;


// 如果根节点有被动副作用,则将相关状态存储起来,等待后续处理;否则,释放根节点的缓存池。
  if (rootDoesHavePassiveEffects) {
    rootDoesHavePassiveEffects = false;
    rootWithPendingPassiveEffects = root;
    pendingPassiveEffectsLanes = lanes;
  } else {
    releaseRootPooledCache(root, remainingLanes);
  }


  // Read this again, since an effect might have updated it
// 获取根节点的待处理优先级车道,如果没有剩余工作,则清除已失败的错误边界。
  remainingLanes = root.pendingLanes;


  //处理剩余工作和调度
  if (remainingLanes === NoLanes) {
    legacyErrorBoundariesThatAlreadyFailed = null;
  }
 
 // 确保根节点被正确调度,以便处理后续的更新。
  ensureRootIsScheduled(root);


  // Read this again, since a passive effect might have updated it
  remainingLanes = root.pendingLanes;


  // 检测无限更新循环,检测是否存在无限更新循环,若存在则增加嵌套更新计数。
  if (
    (enableInfiniteRenderLoopDetection &&
      (didIncludeRenderPhaseUpdate || didIncludeCommitPhaseUpdate)) ||
    // Was the finished render the result of an update (not hydration)?
    (includesSomeLane(lanes, UpdateLanes) &&
      // Did it schedule a sync update?
      includesSomeLane(remainingLanes, SyncUpdateLanes))
  ) {
    if (root === rootWithNestedUpdates) {
      nestedUpdateCount++;
    } else {
      nestedUpdateCount = 0;
      rootWithNestedUpdates = root;
    }
  } else {
    nestedUpdateCount = 0;
  }


  // If layout work was scheduled, flush it now.
  // 刷新同步工作
  flushSyncWorkOnAllRoots();


  return null;
}

当根节点或子节点存在BeforeMutation、Mutation、Layout 或 Passiv副作用时,会执行:

  1. commitBeforeMutationEffects,是 React 渲染流程中提交阶段的一部分,主要用于在进行 DOM 突变(如更新、插入、删除节点)之前执行一些必要的准备工作和副作用操作。该函数会处理焦点管理、标记需要执行的副作用,并返回一个布尔值,指示是否应该触发在活动实例失去焦点后执行的回调。
  2. commitMutationEffects,数是 React 渲染流程中提交阶段的关键部分,它主要负责执行 DOM 突变(如插入、更新、删除节点)相关的副作用操作。此函数会在 React 完成协调阶段(reconciliation)后,将计算出的 DOM 变更应用到实际的 DOM 树上。
  3. commitLayoutEffects,是 React 提交阶段(Commit Phase)中的一个关键函数,主要负责执行布局副作用(Layout Effects)。在 React 的渲染流程中,当协调阶段(Reconciliation Phase)完成后,会进入提交阶段,这个阶段会将协调阶段计算出的变更应用到实际的 DOM 上。布局副作用是在 DOM 更新后立即执行的副作用,通常用于获取 DOM 节点的布局信息,如元素的宽度、高度等。
  4. requestPaint,用于请求浏览器进行一次重绘操作。

flushPassiveEffects函数

flushPassiveEffects 函数主要用于处理 React 中的被动副作用(passive effects)。被动副作用通常是指在渲染完成后异步执行的副作用,例如 useEffect 钩子中的一些操作。该函数会检查是否存在待处理的被动副作用,如果存在,则调用 flushPassiveEffectsImpl 函数来实际执行这些副作用,并在执行前后进行状态的保存和恢复,确保操作的正确性和状态的一致性。

function flushPassiveEffects(wasDelayedCommit?: boolean): boolean {
// rootWithPendingPassiveEffects 是一个全局变量,用于存储存在待处理被动副作用的根节点。
//如果该变量不为 null,则表示存在待处理的被动副作用,继续执行后续操作。
  if (rootWithPendingPassiveEffects !== null) {
    // 获取存在待处理被动副作用的根节点。
    const root = rootWithPendingPassiveEffects;


    // 获取待处理被动副作用剩余的渲染优先级车道。
    const remainingLanes = pendingPassiveEffectsRemainingLanes;


    // 将待处理被动副作用剩余的渲染优先级车道重置为 NoLanes,表示已经开始处理这些副作用。
    pendingPassiveEffectsRemainingLanes = NoLanes;


    // lanesToEventPriority 函数将待处理被动副作用的渲染优先级车道转换为事件优先级。
    const renderPriority = lanesToEventPriority(pendingPassiveEffectsLanes);
    // 调用 lowerEventPriority 函数,取 DefaultEventPriority 和 renderPriority 中的较低优先级作为最终的执行优先级
    const priority = lowerEventPriority(DefaultEventPriority, renderPriority);
    const prevTransition = ReactSharedInternals.T;


    // 当前的更新优先级
    const previousPriority = getCurrentUpdatePriority();


    try {
      setCurrentUpdatePriority(priority);
      ReactSharedInternals.T = null;
      // 调用 flushPassiveEffectsImpl 函数实际执行被动副作用,并返回该函数的执行结果。
      return flushPassiveEffectsImpl(wasDelayedCommit);
    } finally {
      // 恢复之前的状态并释放根节点的缓存
      setCurrentUpdatePriority(previousPriority);
      ReactSharedInternals.T = prevTransition;
      // 释放根节点的缓存,传入根节点和剩余的渲染优先级车道作为参数。
      releaseRootPooledCache(root, remainingLanes);
    }
  }


  // 不存在待处理的被动副作用,直接返回 false。
  return false;
}

flushPassiveEffectsImpl

flushPassiveEffectsImpl 函数的主要作用是刷新待处理的被动副作用。被动副作用通常和 React 的 useEffect 钩子相关,在渲染完成后异步执行。此函数会处理组件卸载和挂载时的被动副作用,同时处理过渡回调和同步工作。

function flushPassiveEffectsImpl(wasDelayedCommit: void | boolean) {
  // 检查是否有待处理的被动副作用
  if (rootWithPendingPassiveEffects === null) {
    return false;
  }


  // Cache and clear the transitions flag
  // 缓存并清除过渡标志
  const transitions = pendingPassiveTransitions;
  pendingPassiveTransitions = null;


  // 获取根节点和车道信息并重置
  const root = rootWithPendingPassiveEffects;
  const lanes = pendingPassiveEffectsLanes;
  rootWithPendingPassiveEffects = null;
  pendingPassiveEffectsLanes = NoLanes;


  // 检查是否正在渲染
  if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
    throw new Error('Cannot flush passive effects while already rendering.');
  }


  // 记录开始时间并设置执行上下文
  let passiveEffectStartTime = 0;
  const prevExecutionContext = executionContext;
  executionContext |= CommitContext;


  // 执行被动卸载和挂载副作用
  commitPassiveUnmountEffects(root.current);
  commitPassiveMountEffects(
    root,
    root.current,
    lanes,
    transitions,
    pendingPassiveEffectsRenderEndTime,
  );


  // 恢复执行上下文
  executionContext = prevExecutionContext;

  // 刷新所有根节点的同步工作
  flushSyncWorkOnAllRoots();


  // 若启用了过渡跟踪功能,缓存当前的过渡回调、根节点过渡回调和结束时间。若这些值都不为 null,将当前的过渡回调和结束时间重置为 null,并在空闲调度优先级下调度 processTransitionCallbacks 函数来处理过渡回调。
  if (enableTransitionTracing) {
    const prevPendingTransitionCallbacks = currentPendingTransitionCallbacks;
    const prevRootTransitionCallbacks = root.transitionCallbacks;
    const prevEndTime = currentEndTime;
    if (
      prevPendingTransitionCallbacks !== null &&
      prevRootTransitionCallbacks !== null &&
      prevEndTime !== null
    ) {
      currentPendingTransitionCallbacks = null;
      currentEndTime = null;
      
      scheduleCallback(IdleSchedulerPriority, () => {
        processTransitionCallbacks(
          prevPendingTransitionCallbacks,
          prevEndTime,
          prevRootTransitionCallbacks,
        );
      });
    }
  }


  return true;
}

commitPassiveUnmountEffects

function commitPassiveUnmountEffects(finishedWork: Fiber): void {
  // resetComponentEffectTimers();
  commitPassiveUnmountOnFiber(finishedWork);
}

commitPassiveUnmountOnFiber

commitPassiveUnmountOnFiber 函数的主要作用是在 React 渲染流程的提交阶段,对指定的 Fiber 节点执行被动卸载副作用的操作。被动卸载副作用通常与 useEffect 钩子的清理函数相关,当组件卸载时,这些清理函数会被调用。该函数会根据 Fiber 节点的不同类型,执行相应的卸载逻辑。

function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {
  // const prevEffectStart = pushComponentEffectStart();


  switch (finishedWork.tag) {
    case FunctionComponent:
    case ForwardRef:
    case SimpleMemoComponent: {
      recursivelyTraversePassiveUnmountEffects(finishedWork);
      if (finishedWork.flags & Passive) {
        
        commitHookPassiveUnmountEffects(
          finishedWork,
          finishedWork.return,
          HookPassive | HookHasEffect,
        );
      }
      break;
    }
    case HostRoot: {
      // const prevEffectDuration = pushNestedEffectDurations();
      recursivelyTraversePassiveUnmountEffects(finishedWork);
 
      break;
    }
    case Profiler: {
      // const prevEffectDuration = pushNestedEffectDurations();


      recursivelyTraversePassiveUnmountEffects(finishedWork);


      break;
    }
    case OffscreenComponent: {
      const instance: OffscreenInstance = finishedWork.stateNode;
      const nextState: OffscreenState | null = finishedWork.memoizedState;


      const isHidden = nextState !== null;


      if (
        isHidden &&
        instance._visibility & OffscreenPassiveEffectsConnected &&
        (finishedWork.return === null ||
          finishedWork.return.tag !== SuspenseComponent)
      ) {
       
        instance._visibility &= ~OffscreenPassiveEffectsConnected;
        recursivelyTraverseDisconnectPassiveEffects(finishedWork);
      } else {
        recursivelyTraversePassiveUnmountEffects(finishedWork);
      }


      break;
    }
    default: {
      recursivelyTraversePassiveUnmountEffects(finishedWork);
      break;
    }
  }
  // popComponentEffectStart(prevEffectStart);
}

recursivelyTraversePassiveUnmountEffects

递归遍历 Fiber 树,处理组件卸载时的被动副作用(如 useEffect 的清理函数)。它主要处理两类逻辑:

  1. 子节点删除:当父节点标记为需要删除子节点(ChildDeletion)时,遍历所有待删除的子节点,执行其被动卸载副作用。
  2. 子树被动副作用:遍历父节点的子树,对每个子节点调用 commitPassiveUnmountOnFiber,处理其被动卸载逻辑。
function recursivelyTraversePassiveUnmountEffects(parentFiber: Fiber): void {
 
  const deletions = parentFiber.deletions;


  // 如果父节点有子节点需要删除
  if ((parentFiber.flags & ChildDeletion) !== NoFlags) {
    if (deletions !== null) {
      for (let i = 0; i < deletions.length; i++) {
        const childToDelete = deletions[i];


        //当前要删除的子节点
        nextEffect = childToDelete;


        // 在子节点被删除前,执行其被动卸载副作用。
        commitPassiveUnmountEffectsInsideOfDeletedTree_begin(
          childToDelete,
          parentFiber,
        );
      }
    }
    // 断开已删除子节点的兄弟节点与旧 Fiber 树(alternate 指针)的连接,避免残留引用导致内存泄漏。
    detachAlternateSiblings(parentFiber);
  }


  // 遍历子树处理被动副作用
  if (parentFiber.subtreeFlags & PassiveMask) {
    let child = parentFiber.child;
    while (child !== null) {
      // 深度优先
      commitPassiveUnmountOnFiber(child);
      // 兄弟节点(广度优先)
      child = child.sibling;
    }
  }
}


commitPassiveUnmountEffectsInsideOfDeletedTree_begin

主要功能是在删除子树时,递归地执行该子树中所有 Fiber 节点的被动卸载副作用。它会遍历子树中的每个 Fiber 节点,对每个节点调用 commitPassiveUnmountInsideDeletedTreeOnFiber 函数来执行具体的卸载逻辑。

function commitPassiveUnmountEffectsInsideOfDeletedTree_begin(
  deletedSubtreeRoot: Fiber,
  nearestMountedAncestor: Fiber | null,
) {
  // 循环遍历 Fiber 节点
  while (nextEffect !== null) {
    const fiber = nextEffect;
    commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor);


     // 处理子节点
    const child = fiber.child;
  
    if (child !== null) {
      child.return = fiber;
      nextEffect = child;
    } else {
      commitPassiveUnmountEffectsInsideOfDeletedTree_complete(
        deletedSubtreeRoot,
      );
    }
  }
}

commitPassiveUnmountEffectsInsideOfDeletedTree_complete

ommitPassiveUnmountEffectsInsideOfDeletedTree_complete 函数的主要功能是在删除子树的被动卸载副作用处理完成后,对删除子树中的 Fiber 节点进行清理工作,确保内存能够被正确释放,避免出现内存泄漏问题。它会遍历子树中的 Fiber 节点,逐个清理节点及其关联资源,并且在遍历过程中根据节点的兄弟节点和父节点信息进行路径回溯。

function commitPassiveUnmountEffectsInsideOfDeletedTree_complete(
  deletedSubtreeRoot: Fiber,
) {
  // 循环遍历 Fiber 节点
  while (nextEffect !== null) {
    const fiber = nextEffect;
    const sibling = fiber.sibling;
    const returnFiber = fiber.return;
    // 清理 Fiber 节点及其关联的资源,确保内存释放和旧节点引用断开。
    detachFiberAfterEffects(fiber);


    // 判断是否到达删除子树的根节点
    if (fiber === deletedSubtreeRoot) {
      nextEffect = null;
      return;
    }


     // 处理兄弟节点
    if (sibling !== null) {
      sibling.return = returnFiber;
      nextEffect = sibling;
      return;
    }


    // 回溯父节点
    nextEffect = returnFiber;
  }
}

commitPassiveUnmountInsideDeletedTreeOnFiber

function commitPassiveUnmountInsideDeletedTreeOnFiber(
  current: Fiber,
  nearestMountedAncestor: Fiber | null,
): void {
  switch (current.tag) {
    case FunctionComponent:
    case ForwardRef:
    case SimpleMemoComponent: {
      commitHookPassiveUnmountEffects(
        current,
        nearestMountedAncestor,
        HookPassive,
      );
      break;
    }
    case LegacyHiddenComponent:
    case OffscreenComponent: {
      if (enableCache) {
        if (
          current.memoizedState !== null &&
          current.memoizedState.cachePool !== null
        ) {
          const cache: Cache = current.memoizedState.cachePool.pool;
          if (cache != null) {
            retainCache(cache);
          }
        }
      }
      break;
    }
    case SuspenseComponent: {
      if (enableTransitionTracing) {
        // We need to mark this fiber's parents as deleted
        const offscreenFiber: Fiber = (current.child: any);
        const instance: OffscreenInstance = offscreenFiber.stateNode;
        const transitions = instance._transitions;
        if (transitions !== null) {
          const abortReason = {
            reason: 'suspense',
            name: current.memoizedProps.unstable_name || null,
          };
          if (
            current.memoizedState === null ||
            current.memoizedState.dehydrated === null
          ) {
            abortParentMarkerTransitionsForDeletedFiber(
              offscreenFiber,
              abortReason,
              transitions,
              instance,
              true,
            );


            if (nearestMountedAncestor !== null) {
              abortParentMarkerTransitionsForDeletedFiber(
                nearestMountedAncestor,
                abortReason,
                transitions,
                instance,
                false,
              );
            }
          }
        }
      }
      break;
    }
    case CacheComponent: {
      if (enableCache) {
        const cache = current.memoizedState.cache;
        releaseCache(cache);
      }
      break;
    }
    case TracingMarkerComponent: {
      if (enableTransitionTracing) {
        // We need to mark this fiber's parents as deleted
        const instance: TracingMarkerInstance = current.stateNode;
        const transitions = instance.transitions;
        if (transitions !== null) {
          const abortReason = {
            reason: 'marker',
            name: current.memoizedProps.name,
          };
          abortParentMarkerTransitionsForDeletedFiber(
            current,
            abortReason,
            transitions,
            null,
            true,
          );


          if (nearestMountedAncestor !== null) {
            abortParentMarkerTransitionsForDeletedFiber(
              nearestMountedAncestor,
              abortReason,
              transitions,
              null,
              false,
            );
          }
        }
      }
      break;
    }
  }
}

detachAlternateSiblings

detachAlternateSiblings 函数的主要作用是断开父 Fiber 节点旧版本(alternate)的子节点之间的兄弟关系。

当需要清理旧的 Fiber 节点时,该函数会将旧 Fiber 节点的子节点之间的兄弟引用断开,从而辅助垃圾回收机制更有效地回收这些不再使用的旧节点。

function detachAlternateSiblings(parentFiber: Fiber) {


  const previousFiber = parentFiber.alternate;
  if (previousFiber !== null) {
    // 检查旧版本父节点是否有子节点
    let detachedChild = previousFiber.child;
    if (detachedChild !== null) {
      // 开父节点与第一个子节点的连接。
      previousFiber.child = null;


      //  遍历并断开子节点的兄弟关系
      do {
        // 下一个子节点(兄弟节点)
        const detachedSibling = detachedChild.sibling;
       //断开其与兄弟节点的连接。
        detachedChild.sibling = null;
        detachedChild = detachedSibling;
      } while (detachedChild !== null);
    }
  }
}

commitPassiveUnmountOnFiber

commitPassiveUnmountOnFiber 函数的主要作用是在 React 渲染流程的提交阶段,对指定的 Fiber 节点执行被动卸载副作用的操作。被动卸载副作用通常与 useEffect 钩子的清理函数相关,当组件卸载时,这些清理函数会被调用。该函数会根据 Fiber 节点的不同类型,执行相应的卸载逻辑。

function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {
  // const prevEffectStart = pushComponentEffectStart();


  switch (finishedWork.tag) {
    case FunctionComponent:
    case ForwardRef:
    case SimpleMemoComponent: {
      recursivelyTraversePassiveUnmountEffects(finishedWork);
      if (finishedWork.flags & Passive) {
        
        commitHookPassiveUnmountEffects(
          finishedWork,
          finishedWork.return,
          HookPassive | HookHasEffect,
        );
      }
      break;
    }
    case HostRoot: {
      // const prevEffectDuration = pushNestedEffectDurations();
      recursivelyTraversePassiveUnmountEffects(finishedWork);
 
      break;
    }
    case Profiler: {
      // const prevEffectDuration = pushNestedEffectDurations();


      recursivelyTraversePassiveUnmountEffects(finishedWork);


      break;
    }
    case OffscreenComponent: {
      const instance: OffscreenInstance = finishedWork.stateNode;
      const nextState: OffscreenState | null = finishedWork.memoizedState;


      const isHidden = nextState !== null;


      if (
        isHidden &&
        instance._visibility & OffscreenPassiveEffectsConnected &&
        (finishedWork.return === null ||
          finishedWork.return.tag !== SuspenseComponent)
      ) {
       
        instance._visibility &= ~OffscreenPassiveEffectsConnected;
        recursivelyTraverseDisconnectPassiveEffects(finishedWork);
      } else {
        recursivelyTraversePassiveUnmountEffects(finishedWork);
      }


      break;
    }
    default: {
      recursivelyTraversePassiveUnmountEffects(finishedWork);
      break;
    }
  }
  // popComponentEffectStart(prevEffectStart);
}

commitHookPassiveUnmountEffects

function commitHookPassiveUnmountEffects(
  finishedWork: Fiber,
  nearestMountedAncestor: null | Fiber,
  hookFlags: HookFlags,
) {
  commitHookEffectListUnmount(
    hookFlags,
    finishedWork,
    nearestMountedAncestor,
  );
}

commitHookEffectListUnmount

commitHookEffectListUnmount 函数的主要功能是在 React 组件卸载时,对符合特定标志(flags)的副作用钩子(如 useEffectuseLayoutEffect 等)执行清理操作。在 React 中,副作用钩子可能会返回一个清理函数,用于在组件卸载时进行资源释放、取消订阅等操作,该函数就是负责调用这些清理函数的。

函数参数含义

  • flags: 类型为 HookFlags,是一个位掩码,用于筛选需要执行卸载操作的副作用钩子。不同的标志代表不同类型的副作用钩子,例如 Layout 标志可能对应 useLayoutEffectPassive 标志可能对应 useEffect
  • finishedWork: 类型为 Fiber,表示已经完成协调的 Fiber 节点,该节点包含了组件的副作用钩子信息。
  • nearestMountedAncestor: 类型为 Fiber | null,表示距离 finishedWork 最近的已挂载的祖先 Fiber 节点,在执行清理操作时可能会用到。
function commitHookEffectListUnmount(
  flags: HookFlags,
  finishedWork: Fiber,
  nearestMountedAncestor: Fiber | null,
) {
  try {
     // 获取副作用队列
    const updateQueue = finishedWork.updateQueue;


    // 获取最后一个
    const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
    
    if (lastEffect !== null) {
   
      const firstEffect = lastEffect.next;
      let effect = firstEffect;
      
      do {
  // 检查当前副作用的 tag 是否与传入的 flags 匹配。如果匹配,说明该副作用需要执行卸载操作。
        if ((effect.tag & flags) === flags) {
          
          // Unmount
          const inst = effect.inst;
          const destroy = inst.destroy;
          if (destroy !== undefined) {
            // 将 inst.destroy 设置为 undefined,表示清理函数已经执行过
            inst.destroy = undefined;
            // 调用 safelyCallDestroy 函数安全地执行清理函数
            safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);


          }
        }
        
        effect = effect.next;
      } while (effect !== firstEffect);
    }
  } catch (error) {
    // captureCommitPhaseError(finishedWork, finishedWork.return, error);
  }
}

flushSyncWorkOnAllRoots

function performSyncWorkOnRoot(root: FiberRoot, lanes: Lanes) {
  // This is the entry point for synchronous tasks that don't go
  // through Scheduler.
  const didFlushPassiveEffects = flushPassiveEffects();


  if (didFlushPassiveEffects) {
   
    return null;
  }


  const forceSync = true;
  performWorkOnRoot(root, lanes, forceSync);
}

工具函数之 detachFiberAfterEffects

detachFiberAfterEffects 函数的作用是在 React 组件卸载或更新完成后,清理 Fiber 节点及其关联的资源,确保内存释放和旧节点引用断开。它主要用于处理已完成副作用(如 DOM 更新、钩子回调)的 Fiber 节点,避免内存泄漏,并为后续的垃圾回收做准备。

function detachFiberAfterEffects(fiber: Fiber) {


  // 断开 alternate 引用并递归清理
  const alternate = fiber.alternate;
  if (alternate !== null) {
    fiber.alternate = null;
    detachFiberAfterEffects(alternate);
  }


  // 清空子节点和副作用相关属性
  fiber.child = null;
  fiber.deletions = null;
  fiber.sibling = null;


   // 处理宿主组件(如 DOM 节点)
  if (fiber.tag === HostComponent) {
    const hostInstance: Instance = fiber.stateNode;
    if (hostInstance !== null) {
      // 调用该函数清理 DOM 节点的关联资源(如事件监听器、自定义数据),确保 DOM 节点安全卸载。
      detachDeletedInstance(hostInstance);
    }
  }
  // 清空 stateNode(指向真实 DOM 节点的引用),避免内存泄漏。
  fiber.stateNode = null;


 // 重置 Fiber 节点状态
  fiber.return = null;
  fiber.dependencies = null;
  fiber.memoizedProps = null;
  fiber.memoizedState = null;
  fiber.pendingProps = null;
  fiber.stateNode = null;


  fiber.updateQueue = null;
}

工具函数之 detachDeletedInstance

function detachDeletedInstance(node: Instance): void {
  delete (node: any)[internalInstanceKey];
  delete (node: any)[internalPropsKey];
  delete (node: any)[internalEventHandlersKey];
  delete (node: any)[internalEventHandlerListenersKey];
  delete (node: any)[internalEventHandlesSetKey];
}

const randomKey = Math.random().toString(36).slice(2);
const internalInstanceKey = '__reactFiber$' + randomKey;
const internalPropsKey = '__reactProps$' + randomKey;
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
const internalEventHandlersKey = '__reactEvents$' + randomKey;
const internalEventHandlerListenersKey = '__reactListeners$' + randomKey;
const internalEventHandlesSetKey = '__reactHandles$' + randomKey;
const internalRootNodeResourcesKey = '__reactResources$' + randomKey;
const internalHoistableMarker = '__reactMarker$' + randomKey;

工具函数之 lanesToEventPriority

lanesToEventPriority 函数的主要功能是将 React 的车道(Lanes)转换为对应的事件优先级(EventPriority)。在 React 的并发模式下,车道系统用于管理不同优先级的更新任务,而事件优先级则用于确定事件处理的紧急程度。该函数会根据传入的车道信息,找出最高优先级的车道,并将其映射为合适的事件优先级。

参数lanes:类型为 Lanes,表示一组车道。在 React 中,Lanes 是一种用于表示多个优先级车道的位掩码数据结构,每个车道代表一个不同的优先级。

function lanesToEventPriority(lanes: Lanes): EventPriority {
  // 获取最高优先级的车道
  const lane = getHighestPriorityLane(lanes);


   // 判断并返回离散事件优先级
  if (!isHigherEventPriority(DiscreteEventPriority, lane)) {
    return DiscreteEventPriority;
  }


  // 判断并返回连续事件优先级
  if (!isHigherEventPriority(ContinuousEventPriority, lane)) {
    return ContinuousEventPriority;
  }
  // 判断 lane 是否包含非空闲工作。
  if (includesNonIdleWork(lane)) {
    return DefaultEventPriority;
  }
  // 返回空闲事件优先级
  return IdleEventPriority;
}

// 表示没有事件优先级,它被映射到 NoLane。
 const NoEventPriority: EventPriority = NoLane;


// 离散事件优先级,映射到 SyncLane。离散事件通常是指那些由用户交互触发的不连续事件,如点击、输入等。SyncLane 表示同步车道,这类事件的更新任务会被立即同步执行,以保证用户交互的即时响应。
 const DiscreteEventPriority: EventPriority = SyncLane;


// 连续事件优先级,对应 InputContinuousLane。连续事件一般是指那些持续的用户交互事件,如滚动、拖动等。InputContinuousLane 用于处理这类连续事件的更新任务,确保在连续交互过程中页面的流畅性。
 const ContinuousEventPriority: EventPriority = InputContinuousLane;


// 默认事件优先级,映射到 DefaultLane。当没有指定特定的事件优先级时,会使用默认优先级。DefaultLane 是一种通用的车道,用于处理大多数普通的更新任务。
 const DefaultEventPriority: EventPriority = DefaultLane;


// 空闲事件优先级,对应 IdleLane。空闲事件是指那些在浏览器空闲时才会执行的任务,对实时性要求较低。IdleLane 中的任务会在浏览器有空闲资源时才会被执行,以避免影响其他高优先级任务的执行。
 const IdleEventPriority: EventPriority = IdleLane;

工具函数之 lowerEventPriority

lowerEventPriority 函数的主要功能是比较两个事件优先级(EventPriority),并返回其中较低的优先级。在 React 的协调和调度机制中,事件优先级用于决定不同任务的执行顺序,确保高优先级的任务能够优先得到处理。

函数参数含义

  • a:类型为 EventPriority,代表第一个需要比较的事件优先级。
  • b:类型为 EventPriority,代表第二个需要比较的事件优先级。

使用三元运算符进行条件判断,具体逻辑如下:

  • a === 0:如果 a 的值为 0,在 React 的优先级体系中,0 可能代表一种特殊的优先级(如最高优先级或者无优先级的特殊情况),此时直接返回 a
  • a > b:如果 a 的值大于 b,根据 React 中事件优先级的定义,值越大优先级越低,所以返回 a
  • 其他情况:如果上述两个条件都不满足,即 a 不为 0 且 a 小于等于 b,则返回 b
function lowerEventPriority(
  a: EventPriority,
  b: EventPriority,
): EventPriority {
  return a === 0 || a > b ? a : b;
}

工具函数之 mergeLanes

mergeLanes 函数的主要功能是合并两个车道(Lanes 或单个 Lane)。在 React 的调度系统里,车道(Lanes)机制用于对不同更新任务的优先级进行管理和区分。该函数借助按位或运算符 | 把两个车道合并成一个新的车道,从而将多个更新任务的优先级信息整合起来。

 function mergeLanes(a: Lanes | Lane, b: Lanes | Lane): Lanes {
  return a | b;
}


const LaneA = 0b0001; // 二进制表示,代表第 1 个车道
const LaneB = 0b0010; // 二进制表示,代表第 2 个车道


const mergedLanes = mergeLanes(LaneA, LaneB);
console.log(mergedLanes.toString(2)); // 输出: 0b0011,代表第 1 个和第 2 个车道的合并

工具函数之 getCurrentUpdatePriority

function getCurrentUpdatePriority(): EventPriority {
  return currentUpdatePriority;
}

工具函数之 setCurrentUpdatePriority

let currentUpdatePriority: EventPriority = NoEventPriority;


function setCurrentUpdatePriority(newPriority: EventPriority): void {
  currentUpdatePriority = newPriority;
}

工具函数之 safelyCallDestroy

 function safelyCallDestroy(
  current: Fiber,// 已完成的fiber
  nearestMountedAncestor: Fiber | null,
  destroy: () => void,
) {
  try {
    // 执行清理回调函数
    destroy();
  } catch (error) {
    // captureCommitPhaseError(current, nearestMountedAncestor, error);
  }
}

工具函数之 detachDeletedInstance

清除实例上的某些属性。调用该函数清理 DOM 节点的关联资源(如事件监听器、自定义数据),确保 DOM 节点安全卸载。

function detachDeletedInstance(node: Instance): void {
  delete (node: any)[internalInstanceKey];
  delete (node: any)[internalPropsKey];
  delete (node: any)[internalEventHandlersKey];
  delete (node: any)[internalEventHandlerListenersKey];
  delete (node: any)[internalEventHandlesSetKey];
}

const randomKey = Math.random().toString(36).slice(2);
const internalInstanceKey = '__reactFiber$' + randomKey;
const internalPropsKey = '__reactProps$' + randomKey;
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
const internalEventHandlersKey = '__reactEvents$' + randomKey;
const internalEventHandlerListenersKey = '__reactListeners$' + randomKey;
const internalEventHandlesSetKey = '__reactHandles$' + randomKey;
const internalRootNodeResourcesKey = '__reactResources$' + randomKey;
const internalHoistableMarker = '__reactMarker$' + randomKey;

全局变量之事件优先级

// 表示没有优先级(初始状态或无效状态)。
export const NoEventPriority: EventPriority = NoLane;
// 离散事件优先级,最高优先级。用于需要立即同步执行的操作,如用户交互(点击、键盘事件)、setState 同步更新。这类操作会打断其他低优先级任务,立即执行。
export const DiscreteEventPriority: EventPriority = SyncLane;
// 连续事件优先级,用于连续触发的事件(如鼠标移动、滚动)。这类操作允许中断低优先级任务,但可以与其他连续任务合并,避免过度渲染。
export const ContinuousEventPriority: EventPriority = InputContinuousLane;
// 默认优先级,用于普通的状态更新(如异步数据加载完成后的更新)。任务会在离散和连续事件之后执行,但比空闲任务优先。
export const DefaultEventPriority: EventPriority = DefaultLane;
// 空闲优先级,最低优先级。用于非紧急任务(如性能优化、统计上报),仅在浏览器空闲时执行,可能被高优先级任务中断或丢弃。
export const IdleEventPriority: EventPriority = IdleLane;

const TotalLanes = 31;


const NoLanes: Lanes = /*                 */ 0b0000000000000000000000000000000;
const NoLane: Lane = /*                   */ 0b0000000000000000000000000000000;


const SyncHydrationLane: Lane = /*        */ 0b0000000000000000000000000000001;
const SyncLane: Lane = /*                 */ 0b0000000000000000000000000000010;
const SyncLaneIndex: number = 1;
const InputContinuousHydrationLane:Lane= /**/0b0000000000000000000000000000100;
const InputContinuousLane: Lane = /*      */ 0b0000000000000000000000000001000;


const DefaultHydrationLane: Lane = /*     */ 0b0000000000000000000000000010000;
const DefaultLane: Lane = /*              */ 0b0000000000000000000000000100000;


const SyncUpdateLanes: Lane = SyncLane | InputContinuousLane | DefaultLane;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2342300.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

目标检测:视觉系统中的CNN-Transformer融合网络

一、背景 无人机&#xff08;UAVs&#xff09;在城市自动巡逻中发挥着重要作用&#xff0c;但它们在图像识别方面面临挑战&#xff0c;尤其是小目标检测和目标遮挡问题。此外&#xff0c;无人机的高速飞行要求检测系统具备实时处理能力。 为解决这些问题&#xff0c;我们提出…

Turso:一个基于 libSQL的分布式数据库

Turso 是一个完全托管的数据库平台&#xff0c;支持在一个组织中创建高达数十万个数据库&#xff0c;并且可以复制到任何地点&#xff0c;包括你自己的服务器&#xff0c;以实现微秒级的访问延迟。你可以通过Turso CLI&#xff08;命令行界面&#xff09;管理群组、数据库和API…

深度学习前沿 | TransNeXt:仿生聚合注意力引领视觉感知新时代

目录 1. 引言 2. 背景与挑战 3. TransNeXt 核心创新 3.1 像素聚合注意力&#xff08;PAA&#xff09; 3.2 长度缩放余弦注意力&#xff08;LSCA&#xff09; 3.3 卷积 GLU&#xff08;ConvGLU&#xff09; 4. 模型架构详解 5. 实验与性能评估 5.1 图像分类&#xff08;I…

C语言-函数-1

以下是我初学C语言的笔记记录&#xff0c;欢迎在评论区留言补充 一&#xff0c;函数分为几类 * 函数分为两类&#xff1a; 一类是库函数&#xff1b;一类是自定义函数 * 库函数&#xff1a; 系统自己带的&#xff0c;在使用时候&#xff0c;要用到头文件&#xff1b; 查询库函…

openwrt作旁路由时的几个常见问题 openwrt作为旁路由配置zerotier 图文讲解

1 先看openwrt时间&#xff0c;一定要保证时间和浏览器和服务器是一致的&#xff0c;不然无法更新 2 openwrt设置旁路由前先测试下&#xff0c;路由器能否ping通主路由&#xff0c;是否能够连接外网&#xff0c;好多旁路由设置完了&#xff0c;发现还不能远程好多就是旁路由本…

Redis 及其在系统设计中的作用

什么是Redis Redis 是一个开源的内存数据结构存储系统&#xff0c;可用作数据库、缓存和消息代理。它因其快速的性能、灵活性和易用性而得到广泛应用。 Redis 数据存储类型 Redis 允许开发人员以各种数据结构&#xff08;例如字符串、位图、位域、哈希、列表、集合、有序集合…

爬虫-oiwiki

我们将BASE_URL 设置为 "https://oi-wiki.org/" 后脚本就会自动开始抓取该url及其子页面的所有内容&#xff0c;并将统一子页面的放在一个文件夹中 import requests from bs4 import BeautifulSoup from urllib.parse import urljoin, urlparse import os import pd…

强化学习核心原理及数学框架

1. 定义与核心思想 强化学习&#xff08;Reinforcement Learning, RL&#xff09;是一种通过智能体&#xff08;Agent&#xff09;与环境&#xff08;Environment&#xff09;的持续交互来学习最优决策策略的机器学习范式。其核心特征为&#xff1a; ​​试错学习​​&#x…

【技术派后端篇】技术派中 Session/Cookie 与 JWT 身份验证技术的应用及实现解析

在现代Web应用开发中&#xff0c;身份验证是保障系统安全的重要环节。技术派在身份验证领域采用了多种技术方案&#xff0c;其中Session/Cookie和JWT&#xff08;JSON Web Token&#xff09;是两种常用的实现方式。本文将详细介绍这两种身份验证技术在技术派中的应用及具体实现…

【基础】Node.js 介绍、安装及npm 和 npx功能了解

前言 后面安装n8n要用到&#xff0c;做一点技术储备。主要是它的两个工具&#xff1a;npm 和 npx。 Node.js介绍 Node.js 是一个免费的、开源的、跨平台的 JavaScript 运行时环境&#xff0c;允许开发人员在浏览器之外编写命令行工具和服务器端脚本&#xff0c;是一个基于 C…

助力网站优化利用AI批量生成文章工具提升质量

哎&#xff0c;有时候觉得写东西这事儿吧&#xff0c;真挺玄乎的。你看着那些大网站的优质内容&#xff0c;会不会突然冒出个念头——这些家伙到底怎么做到日更十篇还不秃头的&#xff1f;前阵子我蹲在咖啡馆里盯着屏幕发呆&#xff0c;突然刷到个帖子说现在用AI写文章能自动纠…

SpringBootTest报错

Unable to find a SpringBootConfiguration, you need to use ContextConfiguration or … 解决方案&#xff1a;在SpringTest注解中添加属性&#xff08;classes &#xff09;填写启动类 如我的启动类是MainApplication.class javax.websocket.server.ServerContainer no…

w~视觉~合集3

我自己的原文哦~ https://blog.51cto.com/whaosoft/12327888 #几个论文 Fast Charging of Energy-dense Lithium-ion Batteries Real-time Short Video Recommendation on Mobile Devices Semantic interpretation for convolutional neural networks: What makes a ca…

Redis安装及入门应用

应用资料&#xff1a;https://download.csdn.net/download/ly1h1/90685065 1.获取文件&#xff0c;并在该文件下执行cmd 2.输入redis-server-lucifer.exe redis.windows.conf&#xff0c;即可运行redis 3.安装redis客户端软件 4.安装后运行客户端软件&#xff0c;输入链接地址…

NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve

//"dev": " NODE_OPTIONS--openssl-legacy-provider vue-cli-service serve" // 修改后&#xff08;Windows 适用&#xff09; "dev": "vue-cli-service serve --openssl-legacy-provider" 升级 Node.js 到 v14&#xff0c;确保依赖…

上篇:深入剖析 BLE 底层物理层与链路层(约5000字)

引言 在无线通信领域,Bluetooth Low Energy(BLE)以其超低功耗、灵活的连接模式和良好的生态支持,成为 IoT 与可穿戴设备的首选技术。要想在实际项目中优化性能、控制功耗、保证可靠通信,必须对 BLE 协议栈的底层细节有深入了解。本篇将重点围绕物理层(PHY)与链路层(Li…

2025 年“泰迪杯”数据挖掘挑战赛B题——基于穿戴装备的身体活动监测问题分析

摘要 本文聚焦于基于穿戴设备采集的加速度计数据,深入研究志愿者在日常活动中的行为特征,构建了多个数学建模框架,实现从身体活动监测、能耗预测、睡眠阶段识别到久坐预警等多个目标。我们依托于多源数据融合与机器学习模型,对人体活动状态进行识别与分析,为健康管理、行…

Linux424 chage密码信息 gpasswd 附属组

https://chat.deepseek.com/a/chat/s/e55a5e85-de97-450d-a19e-2c48f6669234

自定义指令简介及用法(vue3)

一介绍 防抖与节流&#xff0c;应用场景有很多&#xff0c;例如&#xff1a;禁止重复提交数据的场景、搜索框输入搜索条件&#xff0c;待输入停止后再开始搜索。 防抖 点击button按钮&#xff0c;设置定时器&#xff0c;在规定的时间内再次点击会重置定时器重新计时&#xf…

【Spring Boot】深入解析:#{} 和 ${}

1.#{} 和 ${}的使用 1.1数据准备 1.1.1.MySQL数据准备 &#xff08;1&#xff09;创建数据库&#xff1a; CREATE DATABASE mybatis_study DEFAULT CHARACTER SET utf8mb4;&#xff08;2&#xff09;使用数据库 -- 使⽤数据数据 USE mybatis_study;&#xff08;3&#xff…