当前位置: 首页 > news >正文

React19源码系列之 事件优先级

事件优先级

React 的合成事件系统与事件优先级机制 共同确保了用户交互的即时响应和复杂渲染任务的高效调度。

事件优先级

特点

离散事件(Discrete Events)

clickkeydownfocus

优先级最高,立即处理,不会被中断

连续事件(Continuous Events)

scrolldragtouchmove

优先级中等,允许被更高优先级中断

默认事件(Default Events)

useEffect、状态更新回调

优先级较低,可被用户交互中断

空闲事件(Idle Events)

如非关键 UI 更新、统计数据上报

仅在浏览器空闲时执行

事件优先级模型: 

// NoEventPriority 表示没有事件优先级
const NoEventPriority: EventPriority = NoLane;// DiscreteEventPriority 表示离散事件优先级,被映射到 SyncLane。离散事件通常是一些用户交互事件,如点击、键盘输入等,这些事件需要立即处理,以保证用户操作的即时响应。SyncLane 是同步车道,在这个车道上的更新任务会立即执行。
const DiscreteEventPriority: EventPriority = SyncLane;// ContinuousEventPriority 表示连续事件优先级,对应 InputContinuousLane。连续事件一般是一些连续的用户交互,如滚动、拖拽等。InputContinuousLane 是用于处理连续输入事件的车道,这些事件需要在一定的时间内持续处理,以保证交互的流畅性。
const ContinuousEventPriority: EventPriority = InputContinuousLane;// DefaultEventPriority 是默认事件优先级,映射到 DefaultLane。当没有明确指定事件优先级时,会使用默认优先级。DefaultLane 是一个通用的车道,用于处理大多数普通的更新任务
const DefaultEventPriority: EventPriority = DefaultLane;// IdleEventPriority 表示空闲事件优先级,与 IdleLane 对应。空闲事件是那些可以在浏览器空闲时执行的任务,例如一些非关键的渲染更新或数据处理。IdleLane 上的任务会在浏览器有空闲时间时才会被执行,以避免影响用户交互的性能。
const IdleEventPriority: EventPriority = IdleLane;

dispatchDiscreteEvent (离散事件)

dispatchDiscreteEvent 函数的主要作用是调度离散事件。

离散事件通常是一些需要立即处理的用户交互事件,如点击、键盘输入等。

该函数会在处理离散事件时,临时设置当前的更新优先级为离散事件优先级,以确保事件能够得到及时处理,处理完成后再恢复之前的更新优先级。

函数参数含义:

  • domEventName:类型为 DOMEventName,表示要调度的原生 DOM 事件名称。
  • eventSystemFlags:类型为 EventSystemFlags,是一个用于存储事件系统相关标志的变量,用于表示事件的不同状态或特性。
  • container:类型为 EventTarget,代表事件发生的容器,通常是一个 DOM 元素。
  • nativeEvent:类型为 AnyNativeEvent,是原生的 DOM 事件对象,包含了事件的详细信息等。
function dispatchDiscreteEvent(domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,container: EventTarget,nativeEvent: AnyNativeEvent,
) {// ReactSharedInternals.T 可能是 React 内部用于管理过渡状态的一个变量。const prevTransition = ReactSharedInternals.T;// 重置,确保离散事件(如点击、输入)不会触发过渡动画,保证即时响应。ReactSharedInternals.T = null;// 获取当前更新的优先级const previousPriority = getCurrentUpdatePriority();try {// 调用 setCurrentUpdatePriority 函数将当前的更新优先级设置为 DiscreteEventPriority,表示当前正在处理离散事件,需要立即处理。setCurrentUpdatePriority(DiscreteEventPriority);// 调度事件dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent);} finally {// 恢复更新优先级和过度状态setCurrentUpdatePriority(previousPriority);ReactSharedInternals.T = prevTransition;}
}
function getCurrentUpdatePriority(): EventPriority {return ReactDOMSharedInternals.p; /* currentUpdatePriority */
}function setCurrentUpdatePriority(newPriority: EventPriority,IntentionallyUnusedArgument?: empty,
): void {ReactDOMSharedInternals.p /* currentUpdatePriority */ = newPriority;
}

dispatchContinuousEvent (连续事件)

dispatchContinuousEvent 函数主要用于调度连续事件。

连续事件通常指的是那些连续发生的用户交互事件,例如滚动、拖拽等操作产生的事件。

该函数的核心逻辑是在处理连续事件时,临时调整当前的更新优先级为连续事件优先级,以确保这些连续事件能按照合适的优先级进行处理,处理完成后再恢复之前的更新优先级和过渡状态。

函数参数含义:

  • domEventName:类型为 DOMEventName,表示要调度的原生 DOM 事件名称。
  • eventSystemFlags:类型为 EventSystemFlags,是一个用于存储事件系统相关标志的变量,用于表示事件的不同状态或特性。
  • container:类型为 EventTarget,代表事件发生的容器,通常是一个 DOM 元素。
  • nativeEvent:类型为 AnyNativeEvent,是原生的 DOM 事件对象,包含了事件的详细信息等。
function dispatchContinuousEvent(domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,container: EventTarget,nativeEvent: AnyNativeEvent,
) {const prevTransition = ReactSharedInternals.T;ReactSharedInternals.T = null;const previousPriority = getCurrentUpdatePriority();try {setCurrentUpdatePriority(ContinuousEventPriority);// 调度事件dispatchEvent(domEventName, eventSystemFlags, container, nativeEvent);} finally {setCurrentUpdatePriority(previousPriority);ReactSharedInternals.T = prevTransition;}
}

dispatchEvent(默认事件)

dispatchEvent 函数是 React 事件系统中用于调度原生 DOM 事件的核心函数。它会根据事件的不同状态和条件,决定如何处理事件,包括检查事件是否启用、查找阻止事件的实例、调用插件事件系统进行事件分发、处理连续事件的排队等。

函数参数含义:

  • domEventName:类型为 DOMEventName,表示要调度的原生 DOM 事件名称。
  • eventSystemFlags:类型为 EventSystemFlags,是一个用于存储事件系统相关标志的变量,用于表示事件的不同状态或特性。
  • container:类型为 EventTarget,代表事件发生的容器,通常是一个 DOM 元素。
  • nativeEvent:类型为 AnyNativeEvent,是原生的 DOM 事件对象,包含了事件的详细信息等。
function dispatchEvent(domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,targetContainer: EventTarget,nativeEvent: AnyNativeEvent,
): void {// 如果 _enabled 标志为 false,表示事件系统未启用,直接返回,不进行后续的事件处理。if (!_enabled) {return;}
// findInstanceBlockingEvent 函数,根据原生事件对象 nativeEvent 查找是否存在阻止该事件的实例。如果存在,返回该实例;如果不存在,返回 null。let blockedOn = findInstanceBlockingEvent(nativeEvent);// 如果 blockedOn 为 null,说明没有实例阻止该事件。if (blockedOn === null) {
// 调用 dispatchEventForPluginEventSystem 函数,将事件信息传递给插件事件系统进行处理。dispatchEventForPluginEventSystem(domEventName,eventSystemFlags,nativeEvent,return_targetInst,targetContainer,);// 调用 clearIfContinuousEvent 函数,根据事件名称和原生事件对象,清除连续事件的相关状态。最后返回,结束事件处理。clearIfContinuousEvent(domEventName, nativeEvent);return;}// 连续事件排队处理// 如果 blockedOn 不为 null,调用 queueIfContinuousEvent 函数尝试将事件排队。if (queueIfContinuousEvent(blockedOn,domEventName,eventSystemFlags,targetContainer,nativeEvent,)) {// 如果排队成功,调用 nativeEvent.stopPropagation() 阻止事件继续传播,并返回。nativeEvent.stopPropagation();return;}// We need to clear only if we didn't queue because// queueing is accumulative.// 如果排队失败,调用 clearIfContinuousEvent 函数清除连续事件的相关状态。clearIfContinuousEvent(domEventName, nativeEvent);// This is not replayable so we'll invoke it but without a target,// in case the event system needs to trace it.// 其他情况分发// 调用 dispatchEventForPluginEventSystem 函数分发事件,但将目标实例设置为 null,以便事件系统进行跟踪dispatchEventForPluginEventSystem(domEventName,eventSystemFlags,nativeEvent,null,targetContainer,);
}

findInstanceBlockingEvent

findInstanceBlockingEvent 是 React 内部用于在事件处理流程中 定位阻塞渲染的实例 的核心函数。

其核心作用是:

  1. 通过事件目标(nativeEventTarget)找到对应的 Fiber 实例(如 ContainerSuspenseInstance
  2. 识别哪些组件实例会阻塞事件的传播或渲染(例如 Suspense 边界、根容器)
function findInstanceBlockingEvent(nativeEvent: AnyNativeEvent,
): null | Container | SuspenseInstance {const nativeEventTarget = getEventTarget(nativeEvent);return findInstanceBlockingTarget(nativeEventTarget);
}

工具函数之 getEventTarget

getEventTarget 是 React 内部用于 规范化事件目标(Event Target) 的工具函数。它从原生事件对象中提取实际触发事件的 DOM 节点,并处理以下边缘情况:

  1. 跨浏览器兼容性:兼容不同浏览器对事件目标的不同实现(如 targetsrcElement
  2. SVG 使用元素处理:处理 SVG 中 <use> 元素的特殊情况
  3. 文本节点归一化:将文本节点(TEXT_NODE)转换为其父元素节点
function getEventTarget(nativeEvent) {// 已弃用的 Event.srcElement 是 Event.target 属性的别名。// https://developer.mozilla.org/zh-CN/docs/Web/API/Event/srcElementlet target = nativeEvent.target || nativeEvent.srcElement || window;// correspondingUseElement属性可以获取到原始SVG元素实例if (target.correspondingUseElement) {target = target.correspondingUseElement;}return target.nodeType === TEXT_NODE ? target.parentNode : target;
}
<svg width="100" height="100"><defs><circle id="circle" cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red"/></defs><use xlink:href="#circle" id="usedCircle" onclick="clickHandler(event)"/>
</svg><script>function clickHandler(event) {var target = event.target;if (target.correspondingUseElement) {target = target.correspondingUseElement;}console.log(target); // 这里可以获取到原始的circle元素}
</script>

工具函数之 findInstanceBlockingTarget

findInstanceBlockingTarget 是 React 内部用于 查找阻塞事件处理的 Fiber 实例 的核心函数。其主要作用是在事件触发时,确定是否存在 Suspense 边界或根容器阻塞事件的正常处理,从而实现对异步组件加载状态的控制。

function findInstanceBlockingTarget(targetNode: Node,
): null | Container | SuspenseInstance {// 存储目标实例return_targetInst = null;// 从 DOM 节点获取对应的 React Fiber 实例(通过 internalInstanceKey 关联)let targetInst = getClosestInstanceFromNode(targetNode);if (targetInst !== null) {// getNearestMountedFiber 会向上查找最近的已挂载 Fiber。如果返回 null,说明整棵树已卸载,直接忽略事件。const nearestMounted = getNearestMountedFiber(targetInst);if (nearestMounted === null) {// This tree has been unmounted already. Dispatch without a target.targetInst = null;} else {const tag = nearestMounted.tag;if (tag === SuspenseComponent) {// 如果目标节点属于 Suspense 组件,返回其 Suspense 实例(如 fallback DOM 节点)const instance = getSuspenseInstanceFromFiber(nearestMounted);// 返回 Suspense 实例,阻止事件传播if (instance !== null) {return instance;}targetInst = null;} else if (tag === HostRoot) {// 根节点本身不处理事件,直接忽略。targetInst = null;// 若最近已挂载节点与目标实例不一致} else if (nearestMounted !== targetInst) {// 说明目标实例已卸载或不在当前渲染树中targetInst = null;}}}return_targetInst = targetInst;// 默认返回 null,允许事件继续传播return null;
}

 工具函数之 getClosestInstanceFromNode

getClosestInstanceFromNode 是 React 内部用于 从 DOM 节点查找最近的 Fiber 实例 的核心函数。其主要作用是:

  • 通过 internalInstanceKey 关联的属性快速定位 Fiber
  • 处理非 React 直接管理的 DOM 节点(向上遍历父节点)
  • 特殊处理 Suspense 边界和脱水状态的组件
function getClosestInstanceFromNode(targetNode: Node): null | Fiber {// internalInstanceKey:React 在 DOM 节点上存储的 Fiber 引用(如 __reactFiber$...)。let targetInst = (targetNode: any)[internalInstanceKey];if (targetInst) {// Don't return HostRoot or SuspenseComponent here.return targetInst;}// If the direct event target isn't a React owned DOM node, we need to look// to see if one of its parents is a React owned DOM node.// 递归向上查找最近的 React 父节点。let parentNode = targetNode.parentNode;while (parentNode) {targetInst =// internalContainerInstanceKey:用于 Portal 容器节点(如 ReactDOM.createPortal 的挂载点)。(parentNode: any)[internalContainerInstanceKey] ||(parentNode: any)[internalInstanceKey];if (targetInst) {const alternate = targetInst.alternate;// 检查当前 Fiber 或其备用(alternate)Fiber 是否有子节点if (targetInst.child !== null ||(alternate !== null && alternate.child !== null)) {// Next we need to figure out if the node that skipped past is// nested within a dehydrated boundary and if so, which one.// 从 DOM 节点向上查找最近的 Suspense 边界节点(通过 __reactSuspenseInstance$... 标识)。let suspenseInstance = getParentSuspenseInstance(targetNode);while (suspenseInstance !== null) {const targetSuspenseInst = suspenseInstance[internalInstanceKey];// 返回 Suspense 边界的 Fiberif (targetSuspenseInst) {return targetSuspenseInst;}suspenseInstance = getParentSuspenseInstance(suspenseInstance);}}return targetInst;}// 如果当前父节点未找到 Fiber,继续向上遍历,直到 parentNode 为 null(到达文档根节点)。targetNode = parentNode;parentNode = targetNode.parentNode;}return null;
}

工具函数之 getParentSuspenseInstance

getParentSuspenseInstance 是 React 内部用于 查找最近的 Suspense 边界实例 的工具函数。其核心作用是:

  • 通过 DOM 节点的 注释标记 识别 Suspense 边界
  • 处理嵌套 Suspense 的层级关系(通过 depth 计数)
  • 为事件处理、水合过程提供 Suspense 上下文信息
function getParentSuspenseInstance(targetInstance: Node,
): null | SuspenseInstance {// 返回当前节点的前一个兄弟节点,没有则返回null.let node = targetInstance.previousSibling;// 记录当前嵌套层级,确保找到最近的 Suspense 边界let depth = 0;// 向左遍历兄弟节点(从当前节点向前查找)while (node) {if (node.nodeType === COMMENT_NODE) {const data = ((node: any).data: string);// 处理开始标记if (data === SUSPENSE_START_DATA ||data === SUSPENSE_FALLBACK_START_DATA ||data === SUSPENSE_PENDING_START_DATA) {// 当 depth=0 时,直接返回当前注释节点(最近的 Suspense 边界)if (depth === 0) {return ((node: any): SuspenseInstance);} else {// 当 depth>0 时,说明遇到了更内层的 Suspense 边界,depth 减 1depth--;}// 处理结束标记} else if (data === SUSPENSE_END_DATA) {// 遇到结束标记时,depth 加 1,平衡嵌套层级depth++;}}node = node.previousSibling;}return null;
}

工具函数之 getNearestMountedFiber

getNearestMountedFiber 是 React 内部用于 查找最近已挂载 Fiber 节点 的核心函数。其核心作用是:

  1. 处理未挂载或正在挂载的节点:通过向上遍历,找到最近的已挂载父节点
  2. 识别已卸载的组件树:若整棵树已卸载,返回 null
  3. 支持并发渲染:正确处理插入(Placement)和水合(Hydrating)状态的节点
function getNearestMountedFiber(fiber: Fiber): null | Fiber {let node = fiber;// 最近挂载节点let nearestMounted: null | Fiber = fiber;// 无 alternate 的节点是新创建的,可能尚未挂载if (!fiber.alternate) {let nextNode: Fiber = node;do {node = nextNode;// 检查节点的 flags 是否包含 Placement 或 Hydratingif ((node.flags & (Placement | Hydrating)) !== NoFlags) {// 最近已挂载节点为其父节点(node.return)nearestMounted = node.return;}nextNode = node.return;} while (nextNode);} else {// 有 alternate 的节点已存在于当前渲染树中while (node.return) {// 直接向上遍历至根节点node = node.return;}}// 若最终到达 HostRoot,说明组件树已挂载,返回最近已挂载节点if (node.tag === HostRoot) {return nearestMounted;}// If we didn't hit the root, that means that we're in an disconnected tree// that has been unmounted.// 若未到达根节点(如遍历到 detached 节点),说明组件树已卸载,返回 nullreturn null;
}

工具函数之 isRootDehydrated

isRootDehydrated 是 React 内部用于 判断根 Fiber 节点是否处于脱水状态(Dehydrated) 的工具函数。在服务端渲染(SSR)场景中,React 会将渲染结果序列化为 HTML 发送到客户端,这些预渲染的内容被标记为 "脱水" 状态。客户端激活(Hydration)阶段,React 通过此函数判断根节点是否需要进行水合操作。

function isRootDehydrated(root: FiberRoot): boolean {// root.current:指向当前已提交的根 Fiber 节点// memoizedState:存储 Fiber 节点的状态信息,对于根节点,包含渲染状态、水合标记等const currentState: RootState = root.current.memoizedState;// isDehydrated 为 true 时,表示根节点包含服务端渲染的脱水内容,需要进行水合// isDehydrated 为 false 时,表示根节点是纯客户端渲染,无需水合return currentState.isDehydrated;
}

工具函数之 getSuspenseInstanceFromFiber

getSuspenseInstanceFromFiber 是 React 内部用于从 Fiber 节点中提取 Suspense 实例(SuspenseInstance 的工具函数。其核心作用是在服务端渲染(SSR)或客户端水合(Hydration)过程中,识别并获取与 Fiber 节点关联的 Suspense 状态,以便处理异步组件的加载状态和阻塞逻辑。

function getSuspenseInstanceFromFiber(fiber: Fiber,
): null | SuspenseInstance {// 仅处理 Suspense 类型的 Fiber 节点if (fiber.tag === SuspenseComponent) {let suspenseState: SuspenseState | null = fiber.memoizedState;// 若当前 Fiber 状态为空,尝试从备用 Fiber(alternate)获取if (suspenseState === null) {// fiber.alternate 指向 current Fiber(已提交的渲染状态)const current = fiber.alternate;if (current !== null) {suspenseState = current.memoizedState;}}if (suspenseState !== null) {// 返回脱水状态的 Suspense 实例return suspenseState.dehydrated;}}return null;
}

dispatchEventForPluginEventSystem

dispatchEventForPluginEventSystem 函数是 React 事件系统中用于调度事件到插件事件系统的核心函数。

它的主要任务是根据事件的相关标志和目标实例,对事件进行预处理,最后在批量更新的上下文中调用 dispatchEventsForPlugins 函数来实际分发事件。

函数参数含义:

  • domEventName:类型为 DOMEventName,表示原生 DOM 事件的名称,如 'click''keydown' 等。
  • eventSystemFlags:类型为 EventSystemFlags,是一个用于存储事件系统相关标志的变量,用于表示事件的不同状态或特性。
  • nativeEvent:类型为 AnyNativeEvent,是原生的 DOM 事件对象,包含了事件发生时的详细信息。
  • targetInst:类型为 null | Fiber,表示事件的目标 Fiber 实例,可能为 null
  • targetContainer:类型为 EventTarget,表示事件发生的目标容器,通常是一个 DOM 元素。
function dispatchEventForPluginEventSystem(domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,nativeEvent: AnyNativeEvent,targetInst: null | Fiber,targetContainer: EventTarget,
): void {// 初始化祖先元素let ancestorInst = targetInst;// 如果事件不是处理非托管节点的事件((eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE) === 0),并且不是非委托事件((eventSystemFlags & IS_NON_DELEGATED) === 0),则进入事件委托相关的处理逻辑。if ((eventSystemFlags & IS_EVENT_HANDLE_NON_MANAGED_NODE) === 0 &&(eventSystemFlags & IS_NON_DELEGATED) === 0) {const targetContainerNode = ((targetContainer: any): Node);if (targetInst !== null) {// 声明一个变量 node 并初始化为 targetInst,targetInst 是事件的目标 Fiber 实例。后续会通过不断更新 node 的值来遍历 Fiber 树。let node: null | Fiber = targetInst;// 通过一个 while 循环遍历 Fiber 树// 使用一个无限循环 while (true) 来遍历 Fiber 树,并且给这个循环添加了一个标签 mainLoop,方便后续使用 continue 或 break 语句控制循环。mainLoop: while (true) {// 如果 node 为 null,说明已经遍历到 Fiber 树的顶部,此时直接返回。if (node === null) {return;}// fiber节点的类型const nodeTag = node.tag;// HostRoot表示根fiberif (nodeTag === HostRoot || nodeTag === HostPortal) {// 获取真实容器的信息let container = node.stateNode.containerInfo;// 调用 isMatchingRootContainer 函数检查这个容器是否与目标容器 targetContainerNode 匹配。if (isMatchingRootContainer(container, targetContainerNode)) {// 如果匹配,则跳出 mainLoop 循环。break;}// 如果当前 Fiber 节点是 HostPortal 类型,从其 return 节点(即父节点)开始向上遍历祖先节点。if (nodeTag === HostPortal) {// node的父节点let grandNode = node.return;while (grandNode !== null) {const grandTag = grandNode.tag;// 对于每个 HostRoot 或 HostPortal 类型的祖先节点,检查其对应的容器是否与目标容器匹配。如果匹配,则直接返回。if (grandTag === HostRoot || grandTag === HostPortal) {const grandContainer = grandNode.stateNode.containerInfo;if (isMatchingRootContainer(grandContainer, targetContainerNode)) {return;}}grandNode = grandNode.return;}}while (container !== null) {// 调用 getClosestInstanceFromNode 函数获取与容器对应的 Fiber 节点 parentNode。const parentNode = getClosestInstanceFromNode(container);// 如果 parentNode 为 null,则直接返回。if (parentNode === null) {return;}const parentTag = parentNode.tag;// 如果 parentNode 的类型是 HostComponent、HostText、HostHoistable 或 HostSingleton,则更新 node 和 ancestorInst 为 parentNodeif (parentTag === HostComponent ||parentTag === HostText ||parentTag === HostHoistable ||parentTag === HostSingleton) {node = ancestorInst = parentNode;// 使用 continue mainLoop 语句跳转到 mainLoop 循环的开始处继续遍历。continue mainLoop;}container = container.parentNode;}}// 移到下一个节点node = node.return;}}}// 批量更新并分发事件batchedUpdates(() =>dispatchEventsForPlugins(domEventName,eventSystemFlags,nativeEvent,ancestorInst,targetContainer,),);
}

工具函数之 isMatchingRootContainer

isMatchingRootContainer 是 React 内部用于 判断两个 DOM 容器是否匹配 的工具函数。

function isMatchingRootContainer(grandContainer: Element,targetContainer: EventTarget,
): boolean {return (grandContainer === targetContainer ||// 注释节点特殊处理(grandContainer.nodeType === COMMENT_NODE &&grandContainer.parentNode === targetContainer));
}

工具函数之 batchedUpdates

batchedUpdates 是 React 中用于 批量处理更新(Batched Updates) 的核心函数,主要目的是 将多个状态更新合并为一次渲染,避免不必要的重复渲染,从而优化性能。

function batchedUpdates(fn, a, b) {if (isInsideEventHandler) {// 如果当前已经在批量更新中,直接执行函数(不重新进入批量模式)return fn(a, b);}// isInsideEventHandler:全局标志位,表示是否正在处理事件回调isInsideEventHandler = true;try {// 调用实际批量逻辑return batchedUpdatesImpl(fn, a, b);} finally {// 恢复标志位isInsideEventHandler = false;// 清理可能的残留任务finishEventHandler();}
}

工具函数之 batchedUpdatesImpl

batchedUpdates 是 React 内部用于 批量处理状态更新 的核心函数,主要作用是将多个状态更新(如 setState)合并为单个渲染流程,以提高性能。

function batchedUpdates<A, R>(fn: A => R, a: A): R {// 并发模式if (disableLegacyMode) {// 直接执行,无批量处理return fn(a);} else {// 传统模式// 标记当前处于批量上下文const prevExecutionContext = executionContext;executionContext |= BatchedContext;try {return fn(a);} finally {executionContext = prevExecutionContext;}}
}

dispatchEventsForPlugins 

dispatchEventsForPlugins 函数是 React 事件系统中负责将事件分发给各个插件进行处理的核心函数。

该函数的主要工作流程是先获取事件的目标元素,然后创建一个空的调度队列,接着调用 extractEvents 函数从事件中提取相关信息并填充到调度队列中,最后调用 processDispatchQueue 函数来处理这个调度队列,从而完成事件的分发和处理。

函数参数含义:

  • domEventName:表示原生 DOM 事件的名称,例如 'click''keydown' 等。
  • eventSystemFlags:是一个用于存储事件系统相关标志的变量,这些标志可以表示事件的不同状态或特性,例如是否为捕获阶段、是否为被动事件等。
  • nativeEvent:原生的 DOM 事件对象,包含了事件发生时的详细信息,如鼠标位置、按键信息等。
  • ancestorInst:表示在 React 的 Fiber 树中找到的合适的祖先 Fiber 实例,事件会在这个祖先实例及其子树中进行分发处理。
  • targetContainer:表示事件发生的目标容器,通常是一个 DOM 元素。
function dispatchEventsForPlugins(domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,nativeEvent: AnyNativeEvent,targetInst: null | Fiber,targetContainer: EventTarget,
): void {// 获取目标元素const nativeEventTarget = getEventTarget(nativeEvent);// 创建调度队列const dispatchQueue: DispatchQueue = [];extractEvents(dispatchQueue,// 调度队列domEventName,//  原生事件名称targetInst,// 目标 Fiber 实例nativeEvent,// 原生事件对象nativeEventTarget,// 事件目标元素eventSystemFlags,// 事件系统标志targetContainer,// 目标容器);// 处理调度队列// processDispatchQueue 函数会遍历调度队列,根据队列中的信息依次调用相应的事件处理程序,从而完成事件的分发和处理。processDispatchQueue(dispatchQueue, eventSystemFlags);
}

工具函数之 extractEvents

extractEvents 函数的主要作用是从原生 DOM 事件中提取事件信息,并将这些信息添加到调度队列中。它通过调用不同的事件插件的 extractEvents 方法来完成这一任务,这些插件负责处理不同类型的事件。首先会调用 SimpleEventPlugin 插件,然后根据 eventSystemFlags 标志判断是否需要处理其他的填充(polyfill)插件。

函数参数含义:

  • dispatchQueue:类型为 DispatchQueue,是一个用于存储事件调度信息的队列,后续会将提取的事件信息添加到这个队列中。
  • domEventName:类型为 DOMEventName,表示原生 DOM 事件的名称,如 'click''keydown' 等。
  • targetInst:类型为 null | Fiber,是事件的目标 Fiber 实例,可能为 null
  • nativeEvent:类型为 AnyNativeEvent,是原生的 DOM 事件对象,包含了事件发生时的详细信息。
  • nativeEventTarget:类型为 null | EventTarget,是事件的目标元素,可能为 null
  • eventSystemFlags:类型为 EventSystemFlags,是一个存储事件系统相关标志的变量,用于表示事件的不同状态或特性。
  • targetContainer:类型为 EventTarget,是事件发生的目标容器,通常是一个 DOM 元素。
import * as BeforeInputEventPlugin from './plugins/BeforeInputEventPlugin';
import * as ChangeEventPlugin from './plugins/ChangeEventPlugin';
import * as EnterLeaveEventPlugin from './plugins/EnterLeaveEventPlugin';
import * as SelectEventPlugin from './plugins/SelectEventPlugin';
import * as SimpleEventPlugin from './plugins/SimpleEventPlugin';
import * as FormActionEventPlugin from './plugins/FormActionEventPlugin';function extractEvents(dispatchQueue: DispatchQueue,domEventName: DOMEventName,targetInst: null | Fiber,nativeEvent: AnyNativeEvent,nativeEventTarget: null | EventTarget,eventSystemFlags: EventSystemFlags,targetContainer: EventTarget,
) {// 调用 SimpleEventPlugin 插件的 extractEvents 方法,将事件的相关信息传递给该方法,让其从事件中提取信息并添加到调度队列 dispatchQueue 中。SimpleEventPlugin 可能负责处理一些简单的、通用的事件类型。SimpleEventPlugin.extractEvents(dispatchQueue,domEventName,targetInst,nativeEvent,nativeEventTarget,eventSystemFlags,targetContainer,);const shouldProcessPolyfillPlugins =(eventSystemFlags & SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS) === 0;// 需要填充插件if (shouldProcessPolyfillPlugins) {EnterLeaveEventPlugin.extractEvents(dispatchQueue,domEventName,targetInst,nativeEvent,nativeEventTarget,eventSystemFlags,targetContainer,);ChangeEventPlugin.extractEvents(dispatchQueue,domEventName,targetInst,nativeEvent,nativeEventTarget,eventSystemFlags,targetContainer,);SelectEventPlugin.extractEvents(dispatchQueue,domEventName,targetInst,nativeEvent,nativeEventTarget,eventSystemFlags,targetContainer,);BeforeInputEventPlugin.extractEvents(dispatchQueue,domEventName,targetInst,nativeEvent,nativeEventTarget,eventSystemFlags,targetContainer,);FormActionEventPlugin.extractEvents(dispatchQueue,domEventName,targetInst,nativeEvent,nativeEventTarget,eventSystemFlags,targetContainer,);}
}

clearIfContinuousEvent 

clearIfContinuousEvent 是 React 事件系统中用于 清理连续事件队列 的辅助函数,主要解决 某些特殊事件类型(如 focusdragmouse 等)在快速连续触发时可能导致的逻辑冲突问题

function clearIfContinuousEvent(domEventName: DOMEventName,nativeEvent: AnyNativeEvent,
): void {switch (domEventName) {case 'focusin':case 'focusout':// 清空queuedFocus队列queuedFocus = null;break;case 'dragenter':case 'dragleave':// 清空queuedDrag队列queuedDrag = null;break;case 'mouseover':case 'mouseout':// 清空queuedMouse队列queuedMouse = null;break;// https://developer.mozilla.org/zh-CN/docs/Web/API/Element/pointerover_eventcase 'pointerover':case 'pointerout': {const pointerId = ((nativeEvent: any): PointerEvent).pointerId;queuedPointers.delete(pointerId);break;}// https://developer.mozilla.org/zh-CN/docs/Web/API/Element/gotpointercapture_event// https://developer.mozilla.org/zh-CN/docs/Web/API/Element/lostpointercapture_eventcase 'gotpointercapture':case 'lostpointercapture': {const pointerId = ((nativeEvent: any): PointerEvent).pointerId;queuedPointerCaptures.delete(pointerId);break;}}
}

type AnyNativeEvent = Event | KeyboardEvent | MouseEvent | TouchEvent;type PointerEvent = Event & {pointerId: number,relatedTarget: EventTarget | null,
};
let queuedFocus: null | QueuedReplayableEvent = null;
let queuedDrag: null | QueuedReplayableEvent = null;
let queuedMouse: null | QueuedReplayableEvent = null;type QueuedReplayableEvent = {blockedOn: null | Container | SuspenseInstance,domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,nativeEvent: AnyNativeEvent,targetContainers: Array<EventTarget>,
};
const queuedPointers: Map<number, QueuedReplayableEvent> = new Map();
const queuedPointerCaptures: Map<number, QueuedReplayableEvent> = new Map();

queueIfContinuousEvent

queueIfContinuousEvent 是 React 事件系统中用于 管理连续事件队列 的核心函数,专门处理那些需要 特殊跟踪的持续性事件(如 focusdragmousepointer 事件)。它的核心作用是将这些事件加入对应的全局队列。

function queueIfContinuousEvent(blockedOn: null | Container | SuspenseInstance,domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,targetContainer: EventTarget,nativeEvent: AnyNativeEvent,
): boolean {// Instead of mutating we could clone the event.switch (domEventName) {case 'focusin': {const focusEvent = ((nativeEvent: any): FocusEvent);queuedFocus = accumulateOrCreateContinuousQueuedReplayableEvent(queuedFocus,blockedOn,domEventName,eventSystemFlags,targetContainer,focusEvent,);// 成功加入队列,返回truereturn true;}case 'dragenter': {const dragEvent = ((nativeEvent: any): DragEvent);// 合并或创建可重放事件queuedDrag = accumulateOrCreateContinuousQueuedReplayableEvent(queuedDrag,blockedOn,domEventName,eventSystemFlags,targetContainer,dragEvent,);return true;}case 'mouseover': {const mouseEvent = ((nativeEvent: any): MouseEvent);// 合并或创建可重放事件 queuedMouse = accumulateOrCreateContinuousQueuedReplayableEvent(queuedMouse,blockedOn,domEventName,eventSystemFlags,targetContainer,mouseEvent,);return true;}case 'pointerover': {const pointerEvent = ((nativeEvent: any): PointerEvent);const pointerId = pointerEvent.pointerId;queuedPointers.set(pointerId,// 合并或创建可重放事件accumulateOrCreateContinuousQueuedReplayableEvent(queuedPointers.get(pointerId) || null,blockedOn,domEventName,eventSystemFlags,targetContainer,pointerEvent,),);return true;}case 'gotpointercapture': {const pointerEvent = ((nativeEvent: any): PointerEvent);const pointerId = pointerEvent.pointerId;queuedPointerCaptures.set(pointerId,// 合并或创建可重放事件accumulateOrCreateContinuousQueuedReplayableEvent(queuedPointerCaptures.get(pointerId) || null,blockedOn,domEventName,eventSystemFlags,targetContainer,pointerEvent,),);return true;}}// 未加入队列,返回falsereturn false;
}

工具函数之 accumulateOrCreateContinuousQueuedReplayableEvent

accumulateOrCreateContinuousQueuedReplayableEvent 是 React 事件系统中用于 合并或创建可重放事件 的关键函数,主要解决 Suspense 阻塞期间连续触发的事件 的高效处理问题。

function accumulateOrCreateContinuousQueuedReplayableEvent(existingQueuedEvent: null | QueuedReplayableEvent,// 已存在的事件对象blockedOn: null | Container | SuspenseInstance,// 阻塞目标(Suspense 或容器)domEventName: DOMEventName,// 事件类型(如 'click')eventSystemFlags: EventSystemFlags, // 事件标志位targetContainer: EventTarget,// 事件目标容器nativeEvent: AnyNativeEvent,// 原生事件对象
): QueuedReplayableEvent {// 如果事件是首次触发,创建一个新的 QueuedReplayableEvent。if (existingQueuedEvent === null ||existingQueuedEvent.nativeEvent !== nativeEvent) {// 创建事件const queuedEvent = createQueuedReplayableEvent(blockedOn,domEventName,eventSystemFlags,targetContainer,nativeEvent,);// 阻塞源if (blockedOn !== null) {const fiber = getInstanceFromNode(blockedOn);if (fiber !== null) {// 服务端渲染// attemptContinuousHydration(fiber);}}return queuedEvent;}// 如果事件已存在(如连续触发),合并标志位和容器信息,避免重复创建。existingQueuedEvent.eventSystemFlags |= eventSystemFlags;const targetContainers = existingQueuedEvent.targetContainers;// 如果目标容器不在现有列表中,将其加入(支持多容器场景,如微前端)if (targetContainer !== null &&targetContainers.indexOf(targetContainer) === -1) {targetContainers.push(targetContainer);}return existingQueuedEvent;
}

工具函数之 createQueuedReplayableEvent

createQueuedReplayableEvent 是 React 事件系统中的一个工厂函数,用于创建一个 可重放的事件对象,主要用于处理因 Suspense 阻塞并发渲染中断 而暂时无法立即处理的事件。

function createQueuedReplayableEvent(blockedOn: null | Container | SuspenseInstance,domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,targetContainer: EventTarget,nativeEvent: AnyNativeEvent,
): QueuedReplayableEvent {return {blockedOn,domEventName,eventSystemFlags,nativeEvent,targetContainers: [targetContainer],};
}
{blockedOn,          // 事件被阻塞的原因(Suspense 实例或容器)domEventName,       // 事件类型(如 'click'、'mouseover')eventSystemFlags,   // 事件系统内部标志(如是否捕获阶段)nativeEvent,        // 原生浏览器事件对象targetContainers: [targetContainer], // 事件目标容器数组
}

工具函数之 getInstanceFromNode

getInstanceFromNode 是 React 内部用于 从 DOM 节点直接获取关联的 Fiber 实例 的辅助函数。

function getInstanceFromNode(node: Node): Fiber | null {const inst =// 普通 React DOM 节点(node: any)[internalInstanceKey] ||// Portal 容器节点(node: any)[internalContainerInstanceKey];if (inst) {const tag = inst.tag;if (tag === HostComponent ||tag === HostText ||tag === SuspenseComponent ||tag === HostHoistable ||tag === HostSingleton ||tag === HostRoot) {return inst;} else {return null;}}return null;
}

processDispatchQueue

processDispatchQueue 是 React 事件系统中用于 批量处理事件队列 的核心函数。

function processDispatchQueue(dispatchQueue: DispatchQueue,eventSystemFlags: EventSystemFlags,
): void {// 判断当前事件阶段(捕获或冒泡)const inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;// 遍历事件队列for (let i = 0; i < dispatchQueue.length; i++) {// event合成事件对象// listeners 事件监听器列表const {event, listeners} = dispatchQueue[i];// 调用 processDispatchQueueItemsInOrder 处理单个事件的监听器processDispatchQueueItemsInOrder(event, listeners, inCapturePhase);
}
type DispatchEntry = {event: ReactSyntheticEvent,listeners: Array<DispatchListener>,
};export type DispatchQueue = Array<DispatchEntry>;
type DispatchListener = {instance: null | Fiber,listener: Function,currentTarget: EventTarget,
};

工具函数之 processDispatchQueueItemsInOrder

processDispatchQueueItemsInOrder 是 React 事件系统中用于 按序执行事件监听器 的核心函数。

function processDispatchQueueItemsInOrder(event: ReactSyntheticEvent,dispatchListeners: Array<DispatchListener>,inCapturePhase: boolean,
): void {let previousInstance;// 捕获阶段if (inCapturePhase) {// 从后往前遍历for (let i = dispatchListeners.length - 1; i >= 0; i--) {const {instance, currentTarget, listener} = dispatchListeners[i];// 检查是否提前终止。(若 instance 变化(切换到新组件)、事件传播已被阻止)if (instance !== previousInstance && event.isPropagationStopped()) {return;}// 调用 executeDispatch 执行事件处理executeDispatch(event, listener, currentTarget);// 更新 previousInstance 记录当前实例previousInstance = instance;}// 冒泡阶段} else {// 从前往后遍历for (let i = 0; i < dispatchListeners.length; i++) {const {instance, currentTarget, listener} = dispatchListeners[i];// 检查是否提前终止if (instance !== previousInstance && event.isPropagationStopped()) {return;}executeDispatch(event, listener, currentTarget);previousInstance = instance;}}
}

executeDispatch

executeDispatch 函数是 React 中用于执行事件监听器的工具函数。它的主要作用是将事件对象、事件监听器和当前事件目标关联起来,然后调用事件监听器处理事件,并在出现异常时进行全局错误报告。

函数参数含义:

  • event: 这是一个 ReactSyntheticEvent 类型的对象,它是 React 对原生 DOM 事件进行封装后的合成事件对象。该对象包含了事件的相关信息,如事件类型、事件触发的位置等。
  • listener: 是一个函数,它是在事件触发时需要执行的事件监听器。这个函数通常是开发者在组件中定义的,用于处理特定的事件。
  • currentTarget: 表示当前事件的目标元素,即绑定了事件监听器的元素。
function executeDispatch(event: ReactSyntheticEvent,listener: Function,currentTarget: EventTarget,
): void {event.currentTarget = currentTarget;// 调用事件监听器并处理异常try {listener(event);} catch (error) {reportGlobalError(error);}// 在事件监听器执行完毕后,将 event 对象的 currentTarget 属性重置为 null。这是为了避免事件对象在后续的使用中保留不必要的引用,防止内存泄漏和潜在的错误。event.currentTarget = null;
}

http://www.xdnf.cn/news/968941.html

相关文章:

  • Netty从入门到进阶(三)
  • 淘宝SKU与视频详情API接口使用指南
  • 6月10日day50打卡
  • 鹰盾播放器禁止录屏操作的深度技术解析与全栈实现方案
  • AI写实数字人实时交互系统本地私有化部署方案
  • Java TCP网络编程核心指南
  • 服务器硬防的应用场景都有哪些?
  • V837s-sdk buildroot文件系统设置串口登录密码
  • Docker 创建及部署完整流程
  • spring jms使用
  • pnpm install 和 npm install 的区别
  • 力扣HOT100之堆:347. 前 K 个高频元素
  • 基于51单片机的三位电子密码锁
  • LDPC码的编码算法
  • 【2025CVPR】花粉识别新标杆:HieraEdgeNet多尺度边缘增强框架详解
  • C++中变量赋值有几种形式
  • [ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
  • Suna 开源 AI Agent 安装配置过程全解析(输出与交互详解)
  • 泊松圆盘采样进行随机选点
  • iOS26 深度解析:WWDC25 重磅系统的设计革新与争议焦点
  • 聊一聊 - 如何像开源项目一样,去设计一个组件
  • (五)docker环境中配置hosts
  • React19源码系列之 事件插件系统
  • 鹰盾视频的AI行为检测是怎样的风控?
  • 黑马python(二)
  • 分析VSS,VCC和VDD
  • 206. 2013年蓝桥杯省赛 - 打印十字图(困难)- 模拟
  • 第三章支线五 ·组件之城 · 构建与复用的魔法工坊
  • 基于数字孪生的水厂可视化平台建设:架构与实践
  • nsight system分析LLM注意事项