How to use flushDiscreteUpdatesIfNeeded method in Playwright Internal

Best JavaScript code snippet using playwright-internal

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

ReactDOMEventListener.js

Source: ReactDOMEventListener.js Github

copy
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10import type {AnyNativeEvent} from '../events/PluginModuleType';
11import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
12import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
13import type {DOMEventName} from '../events/DOMEventNames';
14
15// Intentionally not named imports because Rollup would use dynamic dispatch for
16// CommonJS interop named imports.
17import * as Scheduler from 'scheduler';
18
19import {
20  isReplayableDiscreteEvent,
21  queueDiscreteEvent,
22  hasQueuedDiscreteEvents,
23  clearIfContinuousEvent,
24  queueIfContinuousEvent,
25} from './ReactDOMEventReplaying';
26import {
27  getNearestMountedFiber,
28  getContainerFromFiber,
29  getSuspenseInstanceFromFiber,
30} from 'react-reconciler/src/ReactFiberTreeReflection';
31import {HostRoot, SuspenseComponent} from 'react-reconciler/src/ReactWorkTags';
32import {
33  type EventSystemFlags,
34  IS_CAPTURE_PHASE,
35  IS_LEGACY_FB_SUPPORT_MODE,
36} from './EventSystemFlags';
37
38import getEventTarget from './getEventTarget';
39import {getClosestInstanceFromNode} from '../client/ReactDOMComponentTree';
40
41import {
42  enableLegacyFBSupport,
43  enableEagerRootListeners,
44  decoupleUpdatePriorityFromScheduler,
45} from 'shared/ReactFeatureFlags';
46import {
47  UserBlockingEvent,
48  ContinuousEvent,
49  DiscreteEvent,
50} from 'shared/ReactTypes';
51import {getEventPriorityForPluginSystem} from './DOMEventProperties';
52import {dispatchEventForPluginEventSystem} from './DOMPluginEventSystem';
53import {
54  flushDiscreteUpdatesIfNeeded,
55  discreteUpdates,
56} from './ReactDOMUpdateBatching';
57import {
58  InputContinuousLanePriority,
59  getCurrentUpdateLanePriority,
60  setCurrentUpdateLanePriority,
61} from 'react-reconciler/src/ReactFiberLane';
62
63const {
64  unstable_UserBlockingPriority: UserBlockingPriority,
65  unstable_runWithPriority: runWithPriority,
66} = Scheduler;
67
68// TODO: can we stop exporting these?
69export let _enabled = true;
70
71// This is exported in FB builds for use by legacy FB layer infra.
72// We'd like to remove this but it's not clear if this is safe.
73export function setEnabled(enabled: ?boolean) {
74  _enabled = !!enabled;
75}
76
77export function isEnabled() {
78  return _enabled;
79}
80
81export function createEventListenerWrapper(
82  targetContainer: EventTarget,
83  domEventName: DOMEventName,
84  eventSystemFlags: EventSystemFlags,
85): Function {
86  return dispatchEvent.bind(
87    null,
88    domEventName,
89    eventSystemFlags,
90    targetContainer,
91  );
92}
93// 按照事件名称,划分事件执行的优先级,处理后返回监听函数
94export function createEventListenerWrapperWithPriority(
95  targetContainer: EventTarget,
96  domEventName: DOMEventName,
97  eventSystemFlags: EventSystemFlags,  
98): Function {
99  const eventPriority = getEventPriorityForPluginSystem(domEventName);  // eventPriorities 中获取当前原生事件的优先级
100  let listenerWrapper;
101  switch (eventPriority) {  // 根据不同的优先级提供不同的监听函数
102    case DiscreteEvent:
103      listenerWrapper = dispatchDiscreteEvent;
104      break;
105    case UserBlockingEvent:
106      listenerWrapper = dispatchUserBlockingUpdate;
107      break;
108    case ContinuousEvent:
109    default:
110      listenerWrapper = dispatchEvent;
111      break;
112  }
113  // 三类监听器的入参其实一样,其函数签名均为:
114  // (domEventName: DOMEventName, eventSystemFlags: EventSystemFlags, targetContainer: EventTarget, nativeEvent: AnyNativeEvent) => void
115  // 前三个参数由当前函数提供,最后一个参数便是原生监听器会拥有的唯一入参 Event 对象
116  return listenerWrapper.bind(
117    null,
118    domEventName,
119    eventSystemFlags,
120    targetContainer,
121  );
122}
123
124function dispatchDiscreteEvent(
125  domEventName,
126  eventSystemFlags,
127  container,
128  nativeEvent,
129) {
130  if (
131    !enableLegacyFBSupport ||
132    // If we are in Legacy FB support mode, it means we've already
133    // flushed for this event and we don't need to do it again.
134    (eventSystemFlags & IS_LEGACY_FB_SUPPORT_MODE) === 0
135  ) {  // flushDiscreteUpdatesIfNeeded 的作用是清除先前积攒的为执行的离散任务,包括但不限于之前触发的离散事件 和 useEffect 的回调,
136    flushDiscreteUpdatesIfNeeded(nativeEvent.timeStamp);  // 主要为了保证当前离散事件所对应的状态时最新的
137  }
138  discreteUpdates(  // 新建一个离散更新
139    dispatchEvent,
140    domEventName,
141    eventSystemFlags,
142    container,
143    nativeEvent,
144  );
145}
146
147function dispatchUserBlockingUpdate(
148  domEventName,
149  eventSystemFlags,
150  container,
151  nativeEvent,
152) {
153  if (decoupleUpdatePriorityFromScheduler) {
154    const previousPriority = getCurrentUpdateLanePriority();
155    try {
156      // TODO: Double wrapping is necessary while we decouple Scheduler priority.
157      setCurrentUpdateLanePriority(InputContinuousLanePriority);
158      runWithPriority(
159        UserBlockingPriority,
160        dispatchEvent.bind(
161          null,
162          domEventName,
163          eventSystemFlags,
164          container,
165          nativeEvent,
166        ),
167      );
168    } finally {
169      setCurrentUpdateLanePriority(previousPriority);
170    }
171  } else {
172    runWithPriority(
173      UserBlockingPriority,
174      dispatchEvent.bind(
175        null,
176        domEventName,
177        eventSystemFlags,
178        container,
179        nativeEvent,
180      ),
181    );
182  }
183}
184
185export function dispatchEvent(
186  domEventName: DOMEventName,
187  eventSystemFlags: EventSystemFlags,
188  targetContainer: EventTarget,
189  nativeEvent: AnyNativeEvent,
190): void {
191  if (!_enabled) {
192    return;
193  }
194  let allowReplay = true;
195  if (enableEagerRootListeners) {
196    // TODO: replaying capture phase events is currently broken
197    // because we used to do it during top-level native bubble handlers
198    // but now we use different bubble and capture handlers.
199    // In eager mode, we attach capture listeners early, so we need
200    // to filter them out until we fix the logic to handle them correctly.
201    // This could've been outside the flag but I put it inside to reduce risk.
202    allowReplay = (eventSystemFlags & IS_CAPTURE_PHASE) === 0;
203  }
204  if (
205    allowReplay &&
206    hasQueuedDiscreteEvents() &&
207    isReplayableDiscreteEvent(domEventName)
208  ) {
209    //如果我们已经有一个离散事件队列,这是另一个离散事件
210    //那么无论目标是什么,我们都不能发送它,因为它们
211    //需要按顺序发送。
212    queueDiscreteEvent(
213      null, // Flags that we're not actually blocked on anything as far as we know.
214      domEventName,
215      eventSystemFlags,
216      targetContainer,
217      nativeEvent,
218    );
219    return;
220  }
221
222  const blockedOn = attemptToDispatchEvent(
223    domEventName,
224    eventSystemFlags,
225    targetContainer,
226    nativeEvent,
227  );
228
229  if (blockedOn === null) {
230    // We successfully dispatched this event.
231    if (allowReplay) {
232      clearIfContinuousEvent(domEventName, nativeEvent);
233    }
234    return;
235  }
236
237  if (allowReplay) {
238    if (isReplayableDiscreteEvent(domEventName)) {
239      // This this to be replayed later once the target is available.
240      queueDiscreteEvent(
241        blockedOn,
242        domEventName,
243        eventSystemFlags,
244        targetContainer,
245        nativeEvent,
246      );
247      return;
248    }
249    if (
250      queueIfContinuousEvent(
251        blockedOn,
252        domEventName,
253        eventSystemFlags,
254        targetContainer,
255        nativeEvent,
256      )
257    ) {
258      return;
259    }
260    // We need to clear only if we didn't queue because
261    // queueing is accummulative.
262    clearIfContinuousEvent(domEventName, nativeEvent);
263  }
264
265  // This is not replayable so we'll invoke it but without a target,
266  // in case the event system needs to trace it.
267  dispatchEventForPluginEventSystem(
268    domEventName,
269    eventSystemFlags,
270    nativeEvent,
271    null,
272    targetContainer,
273  );
274}
275
276// Attempt dispatching an event. Returns a SuspenseInstance or Container if it's blocked.
277export function attemptToDispatchEvent(
278  domEventName: DOMEventName,
279  eventSystemFlags: EventSystemFlags,
280  targetContainer: EventTarget,
281  nativeEvent: AnyNativeEvent,
282): null | Container | SuspenseInstance {
283  // TODO: Warn if _enabled is false.
284  //将nativeTarget和v-dom中的node对应上
285  //react会在每个渲染后的真实dom上的每个HTMLElement都设置一个相同的随机属性名,方便对应和查找
286  const nativeEventTarget = getEventTarget(nativeEvent);
287  let targetInst = getClosestInstanceFromNode(nativeEventTarget);
288
289  if (targetInst !== null) {
290    const nearestMounted = getNearestMountedFiber(targetInst);
291    if (nearestMounted === null) {
292      // This tree has been unmounted already. Dispatch without a target.
293      targetInst = null;
294    } else {
295      const tag = nearestMounted.tag;
296      if (tag === SuspenseComponent) {
297        const instance = getSuspenseInstanceFromFiber(nearestMounted);
298        if (instance !== null) {
299          // Queue the event to be replayed later. Abort dispatching since we
300          // don't want this event dispatched twice through the event system.
301          // TODO: If this is the first discrete event in the queue. Schedule an increased
302          // priority for this boundary.
303          return instance;
304        }
305        // This shouldn't happen, something went wrong but to avoid blocking
306        // the whole system, dispatch the event without a target.
307        // TODO: Warn.
308        targetInst = null;
309      } else if (tag === HostRoot) {
310        const root: FiberRoot = nearestMounted.stateNode;
311        if (root.hydrate) {
312          // If this happens during a replay something went wrong and it might block
313          // the whole system.
314          return getContainerFromFiber(nearestMounted);
315        }
316        targetInst = null;
317      } else if (nearestMounted !== targetInst) {
318        // If we get an event (ex: img onload) before committing that
319        // component's mount, ignore it for now (that is, treat it as if it was an
320        // event on a non-React tree). We might also consider queueing events and
321        // dispatching them after the mount.
322        targetInst = null;
323      }
324    }
325  }
326  dispatchEventForPluginEventSystem(
327    domEventName,
328    eventSystemFlags,
329    nativeEvent,
330    targetInst,
331    targetContainer,
332  );
333  // We're not blocked on anything.
334  return null;
335}
336
Full Screen

flushDiscreteUpdatesIfNeeded.js

Source: flushDiscreteUpdatesIfNeeded.js Github

copy
1function flushDiscreteUpdatesIfNeeded(timeStamp) {
2    // event.timeStamp isn't overly reliable due to inconsistencies in
3    // how different browsers have historically provided the time stamp.
4    // Some browsers provide high-resolution time stamps for all events,
5    // some provide low-resolution time stamps for all events. FF < 52
6    // even mixes both time stamps together. Some browsers even report
7    // negative time stamps or time stamps that are 0 (iOS9) in some cases.
8    // Given we are only comparing two time stamps with equality (!==),
9    // we are safe from the resolution differences. If the time stamp is 0
10    // we bail-out of preventing the flush, which can affect semantics,
11    // such as if an earlier flush removes or adds event listeners that
12    // are fired in the subsequent flush. However, this is the same
13    // behaviour as we had before this change, so the risks are low.
14    if (!isInsideEventHandler && (!enableFlareAPI || timeStamp === 0 || lastFlushedEventTimeStamp !== timeStamp)) {
15        lastFlushedEventTimeStamp = timeStamp;
16        flushDiscreteUpdatesImpl();
17    }
18}
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Playwright Internal on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)