React19源码阅读之commitRoot
commitRoot入口
在finishConcurrentRender函数,commitRootWhenReady函数,commitRoot函数。
commitRoot流程图
commitRoot函数
commitRoot
函数是 React 渲染流程中用于提交根节点的关键函数。它的主要作用是设置相关的优先级和状态,然后调用 commitRootImpl
函数来实际执行根节点的提交操作,最后在操作完成后恢复之前的状态。
函数参数含义
- root: 类型为 FiberRoot,代表 React 应用的根节点,包含了整个应用的渲染信息。
- recoverableErrors: 类型为 null | Array<CapturedValue<mixed>>,是一个可恢复错误的数组,用于处理在渲染过程中捕获到的可恢复错误。
- transitions: 类型为 Array<Transition> | null,表示渲染过程中涉及的过渡任务数组。
- didIncludeRenderPhaseUpdate: 布尔类型,指示渲染阶段是否包含更新操作。
- spawnedLane: 类型为 Lane,表示在渲染过程中产生的新的渲染优先级车道。
- updatedLanes: 类型为 Lanes,表示在渲染过程中更新的渲染优先级车道。
- suspendedRetryLanes: 类型为 Lanes,表示暂停后重试的渲染优先级车道。
- suspendedCommitReason: 类型为 SuspendedCommitReason,是一个仅用于性能分析的参数,指示提交操作被暂停的原因。
- completedRenderStartTime: 数值类型,是一个仅用于性能分析的参数,记录渲染开始的时间。
- 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 上,并执行相关的副作用操作。
- 更新 DOM:将
Fiber
树的变化应用到真实的 DOM 上,完成视图的更新。 - 执行副作用:处理各种副作用,包括
useEffect
、useLayoutEffect
等钩子函数的执行,以及生命周期方法的调用。 - 清理和重置状态:在提交完成后,清理和重置相关的状态,为下一次渲染做准备
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 itremainingLanes = 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副作用时,会执行:
- commitBeforeMutationEffects,是 React 渲染流程中提交阶段的一部分,主要用于在进行 DOM 突变(如更新、插入、删除节点)之前执行一些必要的准备工作和副作用操作。该函数会处理焦点管理、标记需要执行的副作用,并返回一个布尔值,指示是否应该触发在活动实例失去焦点后执行的回调。
- commitMutationEffects,数是 React 渲染流程中提交阶段的关键部分,它主要负责执行 DOM 突变(如插入、更新、删除节点)相关的副作用操作。此函数会在 React 完成协调阶段(reconciliation)后,将计算出的 DOM 变更应用到实际的 DOM 树上。
- commitLayoutEffects,是 React 提交阶段(Commit Phase)中的一个关键函数,主要负责执行布局副作用(Layout Effects)。在 React 的渲染流程中,当协调阶段(Reconciliation Phase)完成后,会进入提交阶段,这个阶段会将协调阶段计算出的变更应用到实际的 DOM 上。布局副作用是在 DOM 更新后立即执行的副作用,通常用于获取 DOM 节点的布局信息,如元素的宽度、高度等。
- 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
的清理函数)。它主要处理两类逻辑:
- 子节点删除:当父节点标记为需要删除子节点(
ChildDeletion
)时,遍历所有待删除的子节点,执行其被动卸载副作用。 - 子树被动副作用:遍历父节点的子树,对每个子节点调用
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 &¤t.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 deletedconst 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 deletedconst 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
)的副作用钩子(如 useEffect
、useLayoutEffect
等)执行清理操作。在 React 中,副作用钩子可能会返回一个清理函数,用于在组件卸载时进行资源释放、取消订阅等操作,该函数就是负责调用这些清理函数的。
函数参数含义
flags
: 类型为HookFlags
,是一个位掩码,用于筛选需要执行卸载操作的副作用钩子。不同的标志代表不同类型的副作用钩子,例如Layout
标志可能对应useLayoutEffect
,Passive
标志可能对应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) {// Unmountconst 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,// 已完成的fibernearestMountedAncestor: 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;
相关文章:
React19源码阅读之commitRoot
commitRoot入口 在finishConcurrentRender函数,commitRootWhenReady函数,commitRoot函数。 commitRoot流程图 commitRoot函数 commitRoot 函数是 React 渲染流程中用于提交根节点的关键函数。它的主要作用是设置相关的优先级和状态,然后调…...
单 例 模 式
设计模式(Design Pattern)说白了就是一套方法论,是我们的前辈们不断试错总结出来的。一般意义上的设计模式有23种,分为创建型、结构型、行为型三大类。今天先拿最简单的单例模式开刀吧。 六大原则 在正式进入设计模式的学习之前&…...
如何在 Postman 中,自动获取 Token 并将其赋值到环境变量
在 Postman 中,你可以通过 预请求脚本(Pre-request Script) 和 测试脚本(Tests) 实现自动获取 Token 并将其赋值到环境变量,下面是完整的操作步骤: ✅ 一、创建获取 Token 的请求 通常这个请求…...
CentOS 7 基于 Nginx 的 HTML 部署全流程指南
一、Nginx 安装(两种主流方式) 1. YUM 安装(推荐新手) # 安装 EPEL 扩展源(部分系统需要) yum install epel-release -y# 安装 Nginx yum install nginx -y# 启动并设置开机自启 systemctl start nginx s…...
spring-ai使用Document存储至milvus的数据结构
1、 spring:application:name: spring-ai-alibaba-rag-milvus-exampleai:dashscope:api-key: sk-xxxxxxoooooovectorstore:milvus:client:host: xxx.ooo.mmm.nnnport: 19530username: rootpassword: MilvusdatabaseName: defaultcollectionName: vector_store#初始化 collecti…...
Milvus(6):Collection 管理分区、管理别名
1 管理分区 分区是一个 Collection 的子集。每个分区与其父集合共享相同的数据结构,但只包含集合中的一个数据子集。本页将帮助你了解如何管理分区。 1.1 分区概述 创建一个 Collection 时,Milvus 也会在该 Collection 中创建一个名为_default 的分区。…...
关于Safari浏览器在ios<16.3版本不支持正则表达式零宽断言的解决办法
异常原因 今天在升级Dify版本的时候发现低版本的ios手机出现了以下报错: SyntaxError: Invalid regular expression: invalid group specifier nameError: Invalid regular expression: invalid group specifier name Call Stack 46 eval [native code] (0:0) ./n…...
设计模式--建造者模式详解
建造者模式 建造者模式也属于创建型模式,它提供了一种创建对象的最佳方式 定义:将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示(假设有不同的建造者实现类,可以产生不同的产品)…...
玩转Docker | Docker部署LMS轻量级音乐工具
玩转Docker | Docker部署LMS轻量级音乐工具 前言一、LMS介绍LMS简介主要特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署LMS服务下载镜像创建容器创建容器检查容器状态检查服务端口安全设置四、访问LMS服务访问LMS首页注册账号五、基本使用上传音乐文…...
【前端】【业务场景】【面试】在前端项目中,当涉及大量数据渲染时,如何提高渲染性能并避免页面卡顿?
大量数据渲染性能优化:四层进阶法 循序渐进:先限量 → 再懒渲 → 后分批 → 终极后台协作 1 虚拟滚动:一次只保留“看得见”的节点 核心思路:固定容器高度,让滚动条滚动 假象 的总长度;可视窗口内…...
数据结构与算法实战:从理论到落地的深度探索
放在前面咯 数据结构与算法实战:从理论到落地的深度探索 数据结构与算法实战:从理论到落地的深度探索 在计算机科学的浩瀚宇宙中,数据结构与算法犹如璀璨星辰,指引着高效程序设计的方向。它们不仅是开发者解决复杂问题的核心利…...
大文件上传Demo及面试要点
大文件上传功能实现原理 - 面试解析 在面试中解释大文件上传功能的实现原理时,可以从以下几个方面进行说明: 1. 分片上传 (Chunked Upload) 实现原理 : 前端将大文件分割为固定大小(如5MB)的多个分片(Chunk)每个分片独立上传,…...
安宝特案例 | 物流仓储头部企业应用AR+作业流,规范日常安全点检,保障消防安全
安全点检管理的真实性缺失将会造成极大损失。 仓储物流行业有仓库面积大、货物堆放密集、包装材料易燃、整体货值高的特点,且造成火灾的隐患包括建筑结构隐患、消防设置失效、货物存放与操作隐患、电气系统问题、人为因素等,因此安全管理被放在重要位置…...
关于 xpath 查找 XML 元素的一点总结
测试环境 Win7 64 python 3.4.0 实践出真知 代码如下,更换不同的 xpath,和 response_to_check 进行测试 实验 1 xpath ".//xmlns:return//xmlns:copeWith" response_to_check \ <soap:Envelope xmlns"http://www.examp.com…...
JavaScript学习教程,从入门到精通,XMLHttpRequest 与 Ajax 请求详解(25)
XMLHttpRequest 与 Ajax 请求详解 一、XMLHttpRequest 概述 XMLHttpRequest (XHR) 是一个 JavaScript API,用于在浏览器和服务器之间传输数据,而无需刷新页面。它是实现 Ajax (Asynchronous JavaScript and XML) 技术的核心。 主要特点: …...
HTML、XHTML 和 XML区别
HTML、XHTML 和 XML 这三兄弟的区别 HTML: 老大哥,负责网页长啥样,性格比较随和,有点小错误也能容忍。XHTML: 二哥,看着像 HTML,但规矩严,是按 XML 的规矩来的 HTML,更规范。XML: 小弟…...
形象解释 HTTP 的四种常见请求方式及其中的区别联系
HTTP 的常见请求方式常见的有四种:GET、POST、PUT、DELETE,它们各自的功能不一样。 🍜 场景比喻:HTTP 请求像“去餐厅点菜” 请求方式行为餐厅比喻说明GET获取数据看菜单/问服务员:你们有什么菜?不带食材、…...
微信小程序根据图片生成背景颜色有效果图
效果图 取得是图片中间10个像素算出背景颜色 .wxml <canvas type"2d" id"imageCanvas" style"--w: {{w}}px;--h: {{h}}px;" /> <view style"background: {{backgroundColor}};"><image bind:tap"updateIndex&qu…...
实时步数统计系统 kafka + spark +redis
基于微服务架构设计并实现了一个实时步数统计系统,采用生产者-消费者模式,利用Kafka实现消息队列,Spark Streaming处理实时数据流,Redis提供高性能数据存储,实现了一个高并发、低延迟的数据处理系统,支持多…...
使用 Docker 安装 SQL Server 2022 并解决 Navicat 连接问题
在使用 Docker 安装 SQL Server 时,很多人可能遇到过无法通过 Navicat 等数据库客户端连接到容器的情况。尤其是尝试使用 mcr.microsoft.com/mssql/server:2022-latest 镜像时,可能会发现 Navicat一直转圈,无法连接到数据库。在这篇博客中&am…...
使用 Node、Express 和 MongoDB 构建一个项目工程
本文将详细介绍如何使用 Node.js Express MongoDB 构建一个完整的 RESTful API 后端项目,涵盖: 项目初始化 Express 服务器搭建 MongoDB 数据库连接 REST API 设计(CRUD 操作) 错误处理与中间件 源码结构与完整代码 部署建…...
基本元器件电阻、电容、电感的高频知识和大厂真题解析
本文首先举例分析各个方向的工程师如何定制化准备硬件岗位面试,各个击破; 然后根据实战经验总结硬件领域中电阻电容电感等的主要笔试、面试高频考题考点; 最后,列出最新最全的基本元器件笔试面试的真题和模拟题,供大家参考。 本专栏预计更新50期左右。当前第3期 一、硬件…...
Unity InputSystem触摸屏问题
最近把Unity打包后的windows软件放到windows触摸屏一体机上测试,发现部分屏幕触摸点击不了按钮,测试了其他应用程序都正常。 这个一体机是这样的,一个电脑机箱,外接一个可以触摸的显示屏,然后UGUI的按钮就间歇性点不了…...
分布式微服务架构,数据库连接池设计策略
在分布式微服务架构中,数据库连接池的设计远比单体应用复杂,涉及资源隔离、连接管理、性能调优和高可用等问题。下面是面向专业软件架构师的系统化分析与策略建议: 一、核心挑战 每个服务独立运行,连接池分散 每个微服务维护自己的…...
差分信号抗噪声原理:
差分信号抗噪声原理: 差分信号除了能很好地解决发送和接收参考点电位不同的问题外,差分信号的另一个重要优势就是在一定条件下其抗干扰能力比单端信号更强。对于单端信号传输,外界对它的干扰噪声直接叠加在信号上,接收端直接检测输…...
【数据分析】酵母实验多指标数据的 R 语言分析与可视化
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载必要的R包数据下载定义函数发育分析(development analysis)数据导入与预处理数据子集创建绘图模型分析两两比较生存分析(survival analysis)数据导入与预处理数据子集创建绘…...
AI | 最近比较火的几个生成式对话 AI
关注:CodingTechWork 引言 生成式对话 AI 正在迅速改变我们与机器交互的方式,从智能助手到内容创作,其应用范围广泛且深远。本文将深入探讨几款当前热门的生成式对话 AI 模型,包括 Kimi、DeepSeek、ChatGPT、文心一言、通义千问和…...
将视频生成视频二维码步骤
如何将视频链接生成二维码 生成与视频关联的二维码通常涉及以下几个方面:选择合适的库或工具、准备视频链接以及将其转换为二维码图像。以下是详细的说明: 使用JavaScript/Vue框架生成二维码 在前端开发中,可以使用 qrcode 或者 vue-qrcod…...
以安科瑞 EMS3.0 为依托,打造网荷储充一体化典范
在“双碳”目标与能源革命的浪潮中,安科瑞电气股份有限公司推出的EMS3.0微电网智慧能源平台,以“源-网-荷-储-充”全链路协同为核心,通过物联网、大数据与AI技术的深度融合,为企业提供了一套智能化、高效化、低碳化的能源管理解决…...
堆和二叉树--数据结构初阶(3)(C/C++)
文章目录 前言理论部分堆的模拟实现:(这里举的大根堆)堆的创建二叉树的遍历二叉树的一些其他功能实现 作业部分 前言 这期的话讲解的是堆和二叉树的理论部分和习题部分 理论部分 二叉树的几个性质:1.对于任意一个二叉树,度为0的节点比度为2的节点多一个 2.对于完全…...
CLIP和SimCLR集成到图像-文本检索系统技术实现步骤和部署方案(代码版)
将 CLIP(多模态对比学习)和 SimCLR(单模态对比学习)集成到 图像-文本检索系统(如搜索引擎、电子商务平台)的技术实现步骤和部署方案,结合代码示例与工程化思路: ### 一、技术实现核心步骤 1. 环境搭建与依赖安装 # 安装 PyTorch(支持 GPU 加速) pip install torch…...
R/G-B/G色温坐标系下对横纵坐标取对数的优势
有些白平衡色温坐标系会分别对横纵坐标取对数运算。 这样做有什么优势呢? 我们知道对数函数对0-1之间的因变量值具有扩展作用。即自变量x变化比较小时,经过对数函数作用后可以把因变量扩展到较大范围内,即x变化较小时,y变化较大,增加了识别数据的识别性。 由于Raw数据中的…...
Java开发工具IntelliJ IDEA v2025.1——全面支持Java 24、整合AI
IntelliJ IDEA 是由 JetBrains 开发的智能 Java IDE,提供代码自动补全、重构工具、框架集成(Spring/JPA 等)、数据库工具和调试支持,通过深度代码分析与跨语言功能优化企业级开发流程,被广泛认可为专业 Java 开发者的高…...
IDEA启动报错Failed to create JVM. JVM path的解决办法
今天修改了 IntelliJ IDEA 2023.1 的配置文件 idea64.exe.vmoptions 后启动报错: if you already hava a JDK installed, define a JAVA_HOME variable in Computer > Systen Properties > System Settings > Environment Variables.Failed to create JV…...
R语言中的常用内置函数
常用的数值函数 常用的字符函数 与概率分布相关的函数 有用的统计函数 数据来源:《数据挖掘与数据分析:基于R语言》王阳 2024年1月出版...
docker容器监控自动恢复
关于实现对docker容器监控以及自动恢复,这里介绍两种实现方案。 方案1: 实现思路: 找到(根据正则表达式)所有待监控的docker容器,此处筛选逻辑根据docker运行状态找到已停止(Exit)类…...
【记录手贱bug日常】IDEA 配置vmoptions后打不开,重新安装,删注册表均无用
今天早上来公司,闲着没事优化优化自己的"锄头"idea,然后想着看看idea用的啥垃圾回收器,后来手动改成了-XX:UseG1GC,满心欢喜觉得没什么问题,直接删除缓存重启,结果不出意料的出问题了,…...
STM32F407使用ESP8266实现阿里云OTA(中)
文章目录 前言一、程序分析二、程序讲解1. main函数2. Get_Version()函数3. esp_Init()函数4. Check_Updata()函数结语前言 从上一章STM32F407使用ESP8266实现阿里云OTA(上)中我们已经对连接阿里云和从阿里云获取升级包的流程非常的熟悉了。所以本章我们进行STM32的程序开发…...
如何利用快照与备份快速恢复服务器的数据
在服务器上利用**快照(Snapshot)**和**备份(Backup)**快速恢复数据,可显著减少停机时间并确保业务连续性。以下是具体操作步骤和最佳实践: --- ### **1. 快照(Snapshot)恢复** **适…...
【Leetcode 每日一题】2799. 统计完全子数组的数目
问题背景 给你一个由 正 整数组成的数组 n u m s nums nums。 如果数组中的某个子数组满足下述条件,则称之为 完全子数组 : 子数组中 不同 元素的数目等于整个数组不同元素的数目。 返回数组中 完全子数组 的数目。 子数组 是数组中的一个连续非空序…...
主流操作系统对比分析(macOS、Linux、Windows、Unix)
主流操作系统对比分析(macOS、Linux、Windows、Unix) 一、系统基本介绍 系统核心特点典型代表macOS苹果公司开发,基于 Unix(BSD),闭源,专为苹果硬件优化,强调用户体验和设计美学。m…...
Qt使用 SQLite 数据库的基本方法
在 Qt 中,使用 SQLite 数据库的基本方法与 MySQL 类似,但 SQLite 是一个轻量级的嵌入式数据库,通常不需要外部数据库服务器。你可以直接在本地磁盘上操作 SQLite 数据库文件。 1. 安装 SQLite 驱动 通常,Qt 默认包含了对 SQLite…...
【刷题系列】LeetCode消失的数字、轮转数组
文章目录 1、消失的数字1.1 题目描述1.2 题目分析 2、轮转数字2.1 题目描述2.2 题目分析 1、消失的数字 原题链接:消失的数字 1.1 题目描述 数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗…...
Unreal Niagara制作SubUV贴图翻页动画
SubUV翻页动画是游戏中的常见功能,通过对每一小块UV进行移动可以模拟动画效果,接下来对下图进行SubUV动画的制作。 (金币测试图下载地址:https://download.csdn.net/download/grayrail/90684422) 最终效果如下: 1.…...
【C++】模版初阶:函数模板、类模板
文章目录 一、为什么要使用模板二、什么是函数模板1、函数模板(1)概念(2)格式(3)原理(4)函数模板的实例化(5)模板参数的匹配原则 2、类模板(1&…...
Kotlin基础知识全面解析(下)
文章目录 第六章:集合与函数式编程6.1 集合概述6.2 集合操作6.3 序列 第七章:协程与异步编程7.1 协程基础7.2 挂起函数7.3 异步与等待7.4 协程上下文与调度器 第八章:Kotlin标准库8.1 作用域函数let函数run函数with函数apply函数also函数 8.2…...
NVIDIA高级辅助驾驶安全报告解析
近期参加了NVIDIA高级辅助驾驶开发者实验室,读了NVIDIA的高级辅助驾驶安全报告白皮书,里面涉及了不少有意思的内容,大致分享下英伟达在高级辅助驾驶领域的安全性上的工作。 最令人印象深刻的是NVIDIA提出的"四大支柱"架构&#x…...
HarmonyOS:一多能力介绍:一次开发,多端部署
概述 如果一个应用需要在多个设备上提供同样的内容,则需要适配不同的屏幕尺寸和硬件,开发成本较高。HarmonyOS 系统面向多终端提供了“一次开发,多端部署”(后文中简称为“一多”)的能力,可以基于一种设计…...
位运算题目:解码异或后的排列
文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题:解码异或后的排列 出处:1734. 解码异或后的排列 难度 6 级 题目描述 要求 有一个整数数组 perm \texttt{perm} perm,是前…...
elasticsearch查询中的特殊字符影响分析
大家先看一个执行的dsl 查询sql,大致的意思是排除某些分类下的商品 GET /productinfos/_search {"from": 0,"query": {"bool": {"must": [{"exists": {"field": "minprice"}},{"bool": {&qu…...