8000 refactor(zone.js): drop passive supported check (#58010) · angular/angular@d4dc7cb · GitHub
[go: up one dir, main page]

Skip to content

Commit d4dc7cb

Browse files
arturovtAndrewKushnir
authored andcommitted
refactor(zone.js): drop passive supported check (#58010)
https://caniuse.com/passive-event-listener Passive event listeners are supported in all major evergreen browsers. Thus, we don't need to check whether passives are supported. PR Close #58010
1 parent 181cc17 commit d4dc7cb

File tree

1 file changed

+102
-60
lines changed

1 file changed

+102
-60
lines changed

packages/zone.js/lib/common/events.ts

Lines changed: 102 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -69,29 +69,15 @@ interface InternalEventTask extends EventTask {
6969
// its invocation if dispatched later.
7070
isRemoved?: boolean;
7171
allRemoved?: boolean;
72-
}
73-
74-
// Note that passive event listeners are now supported by most modern browsers,
75-
// including Chrome, Firefox, Safari, and Edge. There's a pending change that
76-
// would remove support for legacy browsers by zone.js. Removing `passiveSupported`
77-
// from the codebase will reduce the final code size for existing apps that still use zone.js.
78-
let passiveSupported = false;
79-
80-
if (typeof window !== 'undefined') {
81-
try {
82-
const options = Object.defineProperty({}, 'passive', {
83-
get: function () {
84-
passiveSupported = true;
85-
},
86-
});
87-
// Note: We pass the `options` object as the event handler too. This is not compatible with the
88-
// signature of `addEventListener` or `removeEventListener` but enables us to remove the handler
89-
// without an actual handler.
90-
window.addEventListener('test', options as any, options);
91-
window.removeEventListener('test', options as any, options);
92-
} catch (err) {
93-
passiveSupported = false;
94-
}
72+
// `originalDelegate` is the actual event listener object passed when
73+
// calling `addEventListener()`, i.e., `{ handleEvent: event => ... }`.
74+
// This object is used to compare event listeners when `addEventListener`
75+
// is called again with the same event listener object reference.
76+
// For example:
77+
// const eventListenerObject = { handleEvent: console.log };
78+
// document.addEventListener('click', eventListenerObject);
79+
// document.addEventListener('click', eventListenerObject);
80+
originalDelegate?: EventListenerObject;
9581
}
9682

9783
// an identifier to tell ZoneTask do not create a new invoke closure
@@ -116,31 +102,92 @@ function prepareEventNames(eventName: string, eventNameToString?: (eventName: st
116102
}
117103

118104
export interface PatchEventTargetOptions {
119-
// validateHandler
105+
/**
106+
* Optional validator for the event handler before patching.
107+
* If it returns false, the handler will not be patched.
108+
*
109+
* @param nativeDelegate The native method (e.g., original addEventListener).
110+
* @param delegate The provided handler function.
111+
* @param target The object being patched.
112+
* @param args The arguments passed to the method.
113+
* @returns Whether the handler is valid for patching.
114+
*/
120115
vh?: (nativeDelegate: any, delegate: any, target: any, args: any) => boolean;
121-
// addEventListener function name
116+
117+
/**
118+
* The property name for the method that adds an event listener.
119+
* Typically `addEventListener`.
120+
*/
122121
add?: string;
123-
// removeEventListener function name
122+
123+
/**
124+
* The property name for the method that removes an event listener.
125+
* Typically `removeEventListener`.
126+
*/
124127
rm?: string;
125-
// prependEventListener function name
128+
129+
/**
130+
* The property name for a method that prepends an event listener.
131+
* Used in some Node.js-style APIs.
132+
*/
126133
prepend?: string;
127-
// listeners function name
134+
135+
/**
136+
* The property name for the method that returns the current listeners.
137+
* `eventListeners` is the default.
138+
*
139+
* Example:
140+
* ```js
141+
* const element = document.querySelector(...);
142+
* console.log(element.eventListeners());
143+
* ```
144+
*/
128145
listeners?: string;
129-
// removeAllListeners function name
146+
147+
/**
148+
* The property name for the method that removes all listeners for an event.
149+
* `removeAllListeners` is the default.
150+
*/
130151
rmAll?: string;
131-
// useGlobalCallback flag
152+
153+
/**
154+
* Indicates whether a shared global callback should be used for all events
155+
* instead of individual per-event callbacks.
156+
*/
132157
useG?: boolean;
133-
// check duplicate flag when addEventListener
158+
159+
/**
160+
* If true, checks for duplicate listeners before adding a new one.
161+
* Prevents multiple registrations of the same handler.
162+
*/
134163
chkDup?: boolean;
135-
// return target flag when addEventListener
164+
165+
/**
166+
* If true, the patched add method will return the target object
167+
* (matching typical `addEventListener` behavior).
168+
*/
136169
rt?: boolean;
137-
// event compare handler
170+
171+
/**
172+
* Optional function to compare existing tasks with a given delegate.
173+
* Used to match handlers when removing or managing listeners.
174+
*
175+
* @param task The internal Zone.js task object.
176+
* @param delegate The original event handler function.
177+
* @returns Whether the two refer to the same handler.
178+
*/
138179
diff?: (task: any, delegate: any) => boolean;
139-
// support passive or not
140-
supportPassive?: boolean;
141-
// get string from eventName (in nodejs, eventName maybe Symbol)
180+
181+
/**
182+
* Converts an event name to a string.
183+
* Useful when event names are symbols (e.g., in Node.js).
184+
*/
142185
eventNameToString?: (eventName: any) => string;
143-
// transfer eventName
186+
187+
/**
188+
* Transforms or normalizes the event name before use.
189+
* Allows remapping or renaming of event types.
190+
*/
144191
transferEventName?: (eventName: string) => string;
145192
}
146193

@@ -322,13 +369,7 @@ export function patchEventTarget(
322369
* to handle all possible input from the user.
323370
*/
324371
function buildEventListenerOptions(options: any, passive: boolean) {
325-
if (!passiveSupported && typeof options === 'object' && options) {
326-
// doesn't support passive but user want to pass an object as options.
327-
// this will not work on some old browser, so we just pass a boolean
328-
// as useCapture parameter
329-
return !!options.capture;
330-
}
331-
if (!passiveSupported || !passive) {
372+
if (!passive) {
332373
return options;
333374
}
334375
if (typeof options === 'boolean') {
@@ -443,8 +484,7 @@ export function patchEventTarget(
443484
);
444485
};
445486

446-
const compare =
447-
patchOptions && patchOptions.diff ? patchOptions.diff : compareTaskCallbackVsDelegate;
487+
const compare = patchOptions?.diff || compareTaskCallbackVsDelegate;
448488

449489
const unpatchedEvents: string[] = (Zone as any)[zoneSymbol('UNPATCHED_EVENTS')];
450490
const passiveEvents: string[] = _global[zoneSymbol('PASSIVE_EVENTS')];
@@ -487,7 +527,7 @@ export function patchEventTarget(
487527
if (patchOptions && patchOptions.transferEventName) {
488528
eventName = patchOptions.transferEventName(eventName);
489529
}
490-
let delegate = arguments[1];
530+
let delegate: EventListenerOrEventListenerObject = arguments[1];
491531
if (!delegate) {
492532
return nativeListener.apply(this, arguments);
493533
}
@@ -496,23 +536,24 @@ export function patchEventTarget(
496536
return nativeListener.apply(this, arguments);
497537
}
498538

499-
// don't create the bind delegate function for handleEvent
500-
// case here to improve addEventListener performance
501-
// we will create the bind delegate when invoke
502-
let isHandleEvent = false;
539+
// To improve `addEventListener` performance, we will create the callback
540+
// for the task later when the task is invoked.
541+
let isEventListenerObject = false;
503542
if (typeof delegate !== 'function') {
543+
// This checks whether the provided listener argument is an object with
544+
// a `handleEvent` method (since we can call `addEventListener` with a
545+
// function `event => ...` or with an object `{ handleEvent: event => ... }`).
504546
if (!delegate.handleEvent) {
505547
return nativeListener.apply(this, arguments);
506548
}
507-
isHandleEvent = true;
549+
isEventListenerObject = true;
508550
}
509551

510552
if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) {
511553
return;
512554
}
513555

514-
const passive =
515-
passiveSupported && !!passiveEvents && passiveEvents.indexOf(eventName) !== -1;
556+
const passive = !!passiveEvents && passiveEvents.indexOf(eventName) !== -1;
516557
const options = copyEventListenerOptions(buildEventListenerOptions(arguments[2], passive));
517558
const signal: AbortSignal | undefined = options?.signal;
518559
if (signal?.aborted) {
@@ -610,7 +651,7 @@ export function patchEventTarget(
610651
// `taskData.options` to pass it to the native `addEventListener`.
611652
const task: InternalEventTask = zone.scheduleEventTask(
612653
source,
613-
delegate,
654+
<Function>delegate,
614655
data,
615656
customScheduleFn,
616657
customCancelFn,
@@ -645,17 +686,18 @@ export function patchEventTarget(
645686
if (once) {
646687
taskData.options.once = true;
647688
}
648-
if (!(!passiveSupported && typeof task.options === 'boolean')) {
649-
// if not support passive, and we pass an option object
650-
// to addEventListener, we should save the options to task
689+
if (typeof task.options !== 'boolean') {
690+
// We should save the options on the task (if it's an object) because
691+
// we'll be using `task.options` later when removing the event listener
692+
// and passing it back to `removeEventListener`.
651693
task.options = options;
652694
}
653695
task.target = target;
654696
task.capture = capture;
655697
task.eventName = eventName;
656-
if (isHandleEvent) {
698+
if (isEventListenerObject) {
657699
// save original delegate for compare to check duplicate
658-
(task as any).originalDelegate = delegate;
700+
task.originalDelegate = <EventListenerObject>delegate;
659701
}
660702
if (!prepend) {
661703
existingTasks.push(task);

0 commit comments

Comments
 (0)
0