Skip to content
目录

在监听了事件后,当事件触发的时候,会执行dispatch方法
如果当前事件是Interactive类型的事件,那么调用的是dispatchInteractiveEvent

Interactive类型的事件

dispatchInteractiveEvent

typescript
function dispatchInteractiveEvent(topLevelType, nativeEvent) {
  interactiveUpdates(dispatchEvent, topLevelType, nativeEvent);
}

interactiveUpdates

typescript
export function interactiveUpdates(fn, a, b) {
  return _interactiveUpdatesImpl(fn, a, b);
}
typescript
let _interactiveUpdatesImpl = function(fn, a, b) {
  return fn(a, b);
};

看到这里,好像跟直接调用dispatchEvent没什么区别。答案其实就在setBatchingImplementation

setBatchingImplementation

typescript
export function setBatchingImplementation(
  batchedUpdatesImpl,
  interactiveUpdatesImpl,
  flushInteractiveUpdatesImpl,
) {
  _batchedUpdatesImpl = batchedUpdatesImpl;
  _interactiveUpdatesImpl = interactiveUpdatesImpl;
  _flushInteractiveUpdatesImpl = flushInteractiveUpdatesImpl;
}

setBatchingImplementation在ReactDOM中引入直接调用了,并且传入了三个参数,也就是修改掉了_interactiveUpdatesImpl的实现

typescript
setBatchingImplementation(
  batchedUpdates,
  interactiveUpdates,
  flushInteractiveUpdates,
);

interactiveUpdates在ReactDOM里的具体实现

这个方法,其实来自react-reconciler包下的ReactFiberScheduler.js中

typescript
function interactiveUpdates<A, B, R>(fn: (A, B) => R, a: A, b: B): R {
  if (
    !isBatchingUpdates &&
    !isRendering &&
    lowestPriorityPendingInteractiveExpirationTime !== NoWork
  ) {
    // 同步执行
    performWork(lowestPriorityPendingInteractiveExpirationTime, false);
    lowestPriorityPendingInteractiveExpirationTime = NoWork;
  }
  const previousIsBatchingUpdates = isBatchingUpdates;
  isBatchingUpdates = true;
  try {
    // 主要就在这里,传入的优先级就是一个用户交互级别的优先级
    return runWithPriority(UserBlockingPriority, () => {
      // 最终调用的fn就是dispatchEvent
      return fn(a, b);
    });
  } finally {
    isBatchingUpdates = previousIsBatchingUpdates;
    if (!isBatchingUpdates && !isRendering) {
      performSyncWork();
    }
  }
}

dispatchEvent

typescript
export function dispatchEvent(
  topLevelType: DOMTopLevelEventType,
  nativeEvent: AnyNativeEvent,
) {
  if (!_enabled) {
    return;
  }
  // 获取原生时间对象的target
  const nativeEventTarget = getEventTarget(nativeEvent);
  // 获取target节点上最近的真实DOM节点挂载的Fiber对象
  let targetInst = getClosestInstanceFromNode(nativeEventTarget);
  // 生成一个bookKeeping对象
  const bookKeeping = getTopLevelCallbackBookKeeping(
    topLevelType,
    nativeEvent,
    targetInst,
  );

  try {
    // 执行batchedUpdates,调用handleTopLevel
    batchedUpdates(handleTopLevel, bookKeeping);
  } finally {
    // 执行完后,重置bookKeeping对象
    releaseTopLevelCallbackBookKeeping(bookKeeping);
  }
}

getClosestInstanceFromNode

typescript
export function getClosestInstanceFromNode(node) {
  // 在创建完DOM节点的时候,挂在了当前的Fiber到当前的DOM上面
  // 所以在这里直接获取好了
  if (node[internalInstanceKey]) {
    return node[internalInstanceKey];
  }
  // 如果没有,会向父节点查找
  while (!node[internalInstanceKey]) {
    if (node.parentNode) {
      node = node.parentNode;
    } else {
      return null;
    }
  }

  let inst = node[internalInstanceKey];
  // 只有是一个真实的DOM节点,才返回,否则返回null
  if (inst.tag === HostComponent || inst.tag === HostText) {
    // In Fiber, this will always be the deepest root.
    return inst;
  }
  return null;
}

getTopLevelCallbackBookKeeping

typescript
function getTopLevelCallbackBookKeeping(
  topLevelType,
  nativeEvent,
  targetInst,
): {
  topLevelType: ?DOMTopLevelEventType,
  nativeEvent: ?AnyNativeEvent,
  targetInst: Fiber | null,
  ancestors: Array<Fiber>,
} {
  // 就是一个bookKeeping的数据结构
  // 这里有一个对象池的概念 减少频繁的对象创建
  // 带来的内存开销, 以提高性能
  if (callbackBookkeepingPool.length) {
    const instance = callbackBookkeepingPool.pop();
    instance.topLevelType = topLevelType;
    instance.nativeEvent = nativeEvent;
    instance.targetInst = targetInst;
    return instance;
  }
  return {
    topLevelType,
    nativeEvent,
    targetInst,
    // 存储的组件bookKeeping节点
    ancestors: [],
  };
}

releaseTopLevelCallbackBookKeeping

typescript
function releaseTopLevelCallbackBookKeeping(instance) {
  instance.topLevelType = null;
  instance.nativeEvent = null;
  instance.targetInst = null;
  instance.ancestors.length = 0;
  if (callbackBookkeepingPool.length < CALLBACK_BOOKKEEPING_POOL_SIZE) {
    callbackBookkeepingPool.push(instance);
  }
}

handleTopLevel

typescript
function handleTopLevel(bookKeeping) {
  let targetInst = bookKeeping.targetInst;
  let ancestor = targetInst;
  do {
    if (!ancestor) {
      // 栈操作
      bookKeeping.ancestors.push(ancestor);
      break;
    }
    // 找到HostRoot 也就是root dom节点
    const root = findRootContainerNode(ancestor);
    if (!root) {
      break;
    }
    bookKeeping.ancestors.push(ancestor);
    // 查找当前DOM节点最近的组件的Fiber 当然只针对HostComponent
    ancestor = getClosestInstanceFromNode(root);
  } while (ancestor);

  for (let i = 0; i < bookKeeping.ancestors.length; i++) {
    // 遍历组件,从最顶部开始,依次对当前DOM节点执行 runExtractedEventsInBatch
    targetInst = bookKeeping.ancestors[i];
    runExtractedEventsInBatch(
      bookKeeping.topLevelType,
      targetInst,
      bookKeeping.nativeEvent,
      getEventTarget(bookKeeping.nativeEvent),
    );
  }
}

runExtractedEventsInBatch

runExtractedEventsInBatch方法来自于events/EventPluginHub.js文件中

typescript
export function runExtractedEventsInBatch(
  topLevelType: TopLevelType,
  targetInst: null | Fiber,
  nativeEvent: AnyNativeEvent,
  nativeEventTarget: EventTarget,
) {
  // 生成事件对象
  const events = extractEvents(
    topLevelType,
    targetInst,
    nativeEvent,
    nativeEventTarget,
  );
  // 在批量中执行events
  runEventsInBatch(events);
}

extractEvents

生成事件对象

typescript
// 提取event对象
function extractEvents(
  topLevelType: TopLevelType,
  targetInst: null | Fiber,
  nativeEvent: AnyNativeEvent,
  nativeEventTarget: EventTarget,
): Array<ReactSyntheticEvent> | ReactSyntheticEvent | null {
  let events = null;
  for (let i = 0; i < plugins.length; i++) {
    // Not every plugin in the ordering may be loaded at runtime.
    const possiblePlugin: PluginModule<AnyNativeEvent> = plugins[i];
    if (possiblePlugin) {
      // 执行插件上生成event对象的方法
      const extractedEvents = possiblePlugin.extractEvents(
        topLevelType,
        targetInst,
        nativeEvent,
        nativeEventTarget,
      );
      if (extractedEvents) {
        // 将注入的插件plugins遍历,然后执行extractEvents
        // 最后将生成的事件对象都汇总到一起,形成一个数组
        events = accumulateInto(events, extractedEvents);
      }
    }
  }
  // 返回生成的事件对象
  return events;
}

accumulateInto

typescript
unction accumulateInto<T>(
  current: ?(Array<T> | T),
  next: T | Array<T>,
): T | Array<T> {
  invariant(
    next != null,
    'accumulateInto(...): Accumulated items must not be null or undefined.',
  );

  if (current == null) {
    return next;
  }

  // Both are not empty. Warning: Never call x.concat(y) when you are not
  // certain that x is an Array (x could be a string with concat method).
  if (Array.isArray(current)) {
    if (Array.isArray(next)) {
      current.push.apply(current, next);
      return current;
    }
    current.push(next);
    return current;
  }

  if (Array.isArray(next)) {
    // A bit too dangerous to mutate `next`.
    return [current].concat(next);
  }

  return [current, next];
}

runEventsInBatch

通过事件对象的生成,得知事件的监听器已经存在了event._dispatchListeners上面,接下来就是在批量更新中执行这个绑定的事件函数

typescript
export function runEventsInBatch(
  events: Array<ReactSyntheticEvent> | ReactSyntheticEvent | null,
) {
  if (events !== null) {
    // 将事件形成一个队列
    eventQueue = accumulateInto(eventQueue, events);
  }
  const processingEventQueue = eventQueue;
  eventQueue = null;

  if (!processingEventQueue) {
    return;
  }
  // 遍历,逐个调用 executeDispatchesAndReleaseTopLevel
  forEachAccumulated(processingEventQueue, executeDispatchesAndReleaseTopLevel);
  // This would be a good time to rethrow if any of the event handlers threw.
  rethrowCaughtError();
}

executeDispatchesAndReleaseTopLevel

typescript
const executeDispatchesAndReleaseTopLevel = function(e) {
  return executeDispatchesAndRelease(e);
};

executeDispatchesAndRelease

typescript
const executeDispatchesAndRelease = function(event: ReactSyntheticEvent) {
  if (event) {
    // 执行
    executeDispatchesInOrder(event);

    if (!event.isPersistent()) {
      event.constructor.release(event);
    }
  }
};

executeDispatchesInOrder

typescript
export function executeDispatchesInOrder(event) {
  // 获取事件对象生成阶段设置的值
  const dispatchListeners = event._dispatchListeners;
  const dispatchInstances = event._dispatchInstances;
  if (Array.isArray(dispatchListeners)) {
    for (let i = 0; i < dispatchListeners.length; i++) {
      if (event.isPropagationStopped()) {
        break;
      }
      // Listeners and Instances are two parallel arrays that are always in sync.
      executeDispatch(event, dispatchListeners[i], dispatchInstances[i]);
    }
  } else if (dispatchListeners) {
    // 开始调用
    executeDispatch(event, dispatchListeners, dispatchInstances);
  }
  event._dispatchListeners = null;
  event._dispatchInstances = null;
}

executeDispatch

typescript
function executeDispatch(event, listener, inst) {
  const type = event.type || 'unknown-event';
  event.currentTarget = getNodeFromInstance(inst);
  invokeGuardedCallbackAndCatchFirstError(type, listener, undefined, event);
  event.currentTarget = null;
}

invokeGuardedCallbackAndCatchFirstError里面针对错误处理了一些场景,最终还是直接调用 listener

备案号: 浙ICP备2023000081号