perf(core): minor improvements to listener instructions (#41807)
Makes the following improvements to the listener instructions to make them slightly smaller and more memory-efficient. 1. Removes the default value from the `useCapture` parameter since it generates more code than just castint to `false`. 2. Removes the `useCapture` and `eventTargetResolver` parameters from `ɵɵsyntheticHostListener` since they won't be generated by the compiler, as far as I can tell. 3. Makes it so that we don't have to return a target name from a `GlobalTargetResolver`. This allows us to save on some memory, because we can return a reference to the target without having to wrap it in an object literal. DEPRECATIONS: `EventManagerPlugin.getGlobalEventTarget` is now deprecated and won't be called from Ivy code anymore. Global events will go through `addEventListener`. PR Close #41807
This commit is contained in:
parent
2dd96e08ae
commit
6581a1b48d
|
@ -32,7 +32,7 @@ export declare const EVENT_MANAGER_PLUGINS: InjectionToken<ɵangular_packages_pl
|
||||||
export declare class EventManager {
|
export declare class EventManager {
|
||||||
constructor(plugins: ɵangular_packages_platform_browser_platform_browser_g[], _zone: NgZone);
|
constructor(plugins: ɵangular_packages_platform_browser_platform_browser_g[], _zone: NgZone);
|
||||||
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function;
|
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function;
|
||||||
addGlobalEventListener(target: string, eventName: string, handler: Function): Function;
|
/** @deprecated */ addGlobalEventListener(target: string, eventName: string, handler: Function): Function;
|
||||||
getZone(): NgZone;
|
getZone(): NgZone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
|
|
||||||
import {assertIndexInRange} from '../../util/assert';
|
import {assertIndexInRange} from '../../util/assert';
|
||||||
import {EMPTY_OBJ} from '../../util/empty';
|
|
||||||
import {isObservable} from '../../util/lang';
|
import {isObservable} from '../../util/lang';
|
||||||
import {PropertyAliasValue, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
import {PropertyAliasValue, TNode, TNodeFlags, TNodeType} from '../interfaces/node';
|
||||||
import {GlobalTargetResolver, isProceduralRenderer, Renderer3} from '../interfaces/renderer';
|
import {GlobalTargetResolver, isProceduralRenderer, Renderer3} from '../interfaces/renderer';
|
||||||
|
@ -39,13 +38,14 @@ import {getOrCreateLViewCleanup, getOrCreateTViewCleanup, handleError, loadCompo
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵlistener(
|
export function ɵɵlistener(
|
||||||
eventName: string, listenerFn: (e?: any) => any, useCapture = false,
|
eventName: string, listenerFn: (e?: any) => any, useCapture?: boolean,
|
||||||
eventTargetResolver?: GlobalTargetResolver): typeof ɵɵlistener {
|
eventTargetResolver?: GlobalTargetResolver): typeof ɵɵlistener {
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
const tView = getTView();
|
const tView = getTView();
|
||||||
const tNode = getCurrentTNode()!;
|
const tNode = getCurrentTNode()!;
|
||||||
listenerInternal(
|
listenerInternal(
|
||||||
tView, lView, lView[RENDERER], tNode, eventName, listenerFn, useCapture, eventTargetResolver);
|
tView, lView, lView[RENDERER], tNode, eventName, listenerFn, !!useCapture,
|
||||||
|
eventTargetResolver);
|
||||||
return ɵɵlistener;
|
return ɵɵlistener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,15 +71,13 @@ export function ɵɵlistener(
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵsyntheticHostListener(
|
export function ɵɵsyntheticHostListener(
|
||||||
eventName: string, listenerFn: (e?: any) => any, useCapture = false,
|
eventName: string, listenerFn: (e?: any) => any): typeof ɵɵsyntheticHostListener {
|
||||||
eventTargetResolver?: GlobalTargetResolver): typeof ɵɵsyntheticHostListener {
|
|
||||||
const tNode = getCurrentTNode()!;
|
const tNode = getCurrentTNode()!;
|
||||||
const lView = getLView();
|
const lView = getLView();
|
||||||
const tView = getTView();
|
const tView = getTView();
|
||||||
const currentDef = getCurrentDirectiveDef(tView.data);
|
const currentDef = getCurrentDirectiveDef(tView.data);
|
||||||
const renderer = loadComponentRenderer(currentDef, tNode, lView);
|
const renderer = loadComponentRenderer(currentDef, tNode, lView);
|
||||||
listenerInternal(
|
listenerInternal(tView, lView, renderer, tNode, eventName, listenerFn, false);
|
||||||
tView, lView, renderer, tNode, eventName, listenerFn, useCapture, eventTargetResolver);
|
|
||||||
return ɵɵsyntheticHostListener;
|
return ɵɵsyntheticHostListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +115,7 @@ function findExistingListener(
|
||||||
|
|
||||||
function listenerInternal(
|
function listenerInternal(
|
||||||
tView: TView, lView: LView, renderer: Renderer3, tNode: TNode, eventName: string,
|
tView: TView, lView: LView, renderer: Renderer3, tNode: TNode, eventName: string,
|
||||||
listenerFn: (e?: any) => any, useCapture = false,
|
listenerFn: (e?: any) => any, useCapture: boolean,
|
||||||
eventTargetResolver?: GlobalTargetResolver): void {
|
eventTargetResolver?: GlobalTargetResolver): void {
|
||||||
const isTNodeDirectiveHost = isDirectiveHost(tNode);
|
const isTNodeDirectiveHost = isDirectiveHost(tNode);
|
||||||
const firstCreatePass = tView.firstCreatePass;
|
const firstCreatePass = tView.firstCreatePass;
|
||||||
|
@ -136,11 +134,10 @@ function listenerInternal(
|
||||||
// add native event listener - applicable to elements only
|
// add native event listener - applicable to elements only
|
||||||
if (tNode.type & TNodeType.AnyRNode) {
|
if (tNode.type & TNodeType.AnyRNode) {
|
||||||
const native = getNativeByTNode(tNode, lView) as RElement;
|
const native = getNativeByTNode(tNode, lView) as RElement;
|
||||||
const resolved = eventTargetResolver ? eventTargetResolver(native) : EMPTY_OBJ as any;
|
const target = eventTargetResolver ? eventTargetResolver(native) : native;
|
||||||
const target = resolved.target || native;
|
|
||||||
const lCleanupIndex = lCleanup.length;
|
const lCleanupIndex = lCleanup.length;
|
||||||
const idxOrTargetGetter = eventTargetResolver ?
|
const idxOrTargetGetter = eventTargetResolver ?
|
||||||
(_lView: LView) => eventTargetResolver(unwrapRNode(_lView[tNode.index])).target :
|
(_lView: LView) => eventTargetResolver(unwrapRNode(_lView[tNode.index])) :
|
||||||
tNode.index;
|
tNode.index;
|
||||||
|
|
||||||
// In order to match current behavior, native DOM event listeners must be added for all
|
// In order to match current behavior, native DOM event listeners must be added for all
|
||||||
|
@ -176,11 +173,8 @@ function listenerInternal(
|
||||||
(<any>existingListener).__ngLastListenerFn__ = listenerFn;
|
(<any>existingListener).__ngLastListenerFn__ = listenerFn;
|
||||||
processOutputs = false;
|
processOutputs = false;
|
||||||
} else {
|
} else {
|
||||||
// The first argument of `listen` function in Procedural Renderer is:
|
|
||||||
// - either a target name (as a string) in case of global target (window, document, body)
|
|
||||||
// - or element reference (in all other cases)
|
|
||||||
listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
|
listenerFn = wrapListener(tNode, lView, context, listenerFn, false /** preventDefault */);
|
||||||
const cleanupFn = renderer.listen(resolved.name || target, eventName, listenerFn);
|
const cleanupFn = renderer.listen(target as RElement, eventName, listenerFn);
|
||||||
ngDevMode && ngDevMode.rendererAddEventListener++;
|
ngDevMode && ngDevMode.rendererAddEventListener++;
|
||||||
|
|
||||||
lCleanup.push(listenerFn, cleanupFn);
|
lCleanup.push(listenerFn, cleanupFn);
|
||||||
|
|
|
@ -30,9 +30,7 @@ export type Renderer3 = ObjectOrientedRenderer3|ProceduralRenderer3;
|
||||||
|
|
||||||
export type GlobalTargetName = 'document'|'window'|'body';
|
export type GlobalTargetName = 'document'|'window'|'body';
|
||||||
|
|
||||||
export type GlobalTargetResolver = (element: any) => {
|
export type GlobalTargetResolver = (element: any) => EventTarget;
|
||||||
name: GlobalTargetName, target: EventTarget
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object Oriented style of API needed to create elements and text nodes.
|
* Object Oriented style of API needed to create elements and text nodes.
|
||||||
|
|
|
@ -23,7 +23,7 @@ export const defaultScheduler =
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵresolveWindow(element: RElement&{ownerDocument: Document}) {
|
export function ɵɵresolveWindow(element: RElement&{ownerDocument: Document}) {
|
||||||
return {name: 'window', target: element.ownerDocument.defaultView};
|
return element.ownerDocument.defaultView;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,7 +31,7 @@ export function ɵɵresolveWindow(element: RElement&{ownerDocument: Document}) {
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵresolveDocument(element: RElement&{ownerDocument: Document}) {
|
export function ɵɵresolveDocument(element: RElement&{ownerDocument: Document}) {
|
||||||
return {name: 'document', target: element.ownerDocument};
|
return element.ownerDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,7 +39,7 @@ export function ɵɵresolveDocument(element: RElement&{ownerDocument: Document})
|
||||||
* @codeGenApi
|
* @codeGenApi
|
||||||
*/
|
*/
|
||||||
export function ɵɵresolveBody(element: RElement&{ownerDocument: Document}) {
|
export function ɵɵresolveBody(element: RElement&{ownerDocument: Document}) {
|
||||||
return {name: 'body', target: element.ownerDocument.body};
|
return element.ownerDocument.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -57,6 +57,7 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
||||||
return node instanceof DocumentFragment;
|
return node instanceof DocumentFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated No longer being used in Ivy code. To be removed in version 14. */
|
||||||
getGlobalEventTarget(doc: Document, target: string): EventTarget|null {
|
getGlobalEventTarget(doc: Document, target: string): EventTarget|null {
|
||||||
if (target === 'window') {
|
if (target === 'window') {
|
||||||
return window;
|
return window;
|
||||||
|
|
|
@ -58,6 +58,7 @@ export class EventManager {
|
||||||
* @param handler A function to call when the notification occurs. Receives the
|
* @param handler A function to call when the notification occurs. Receives the
|
||||||
* event object as an argument.
|
* event object as an argument.
|
||||||
* @returns A callback function that can be used to remove the handler.
|
* @returns A callback function that can be used to remove the handler.
|
||||||
|
* @deprecated No longer being used in Ivy code. To be removed in version 14.
|
||||||
*/
|
*/
|
||||||
addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
|
addGlobalEventListener(target: string, eventName: string, handler: Function): Function {
|
||||||
const plugin = this._findPluginFor(eventName);
|
const plugin = this._findPluginFor(eventName);
|
||||||
|
|
|
@ -62,6 +62,7 @@ export class DominoAdapter extends BrowserDomAdapter {
|
||||||
return node.shadowRoot == node;
|
return node.shadowRoot == node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated No longer being used in Ivy code. To be removed in version 14. */
|
||||||
getGlobalEventTarget(doc: Document, target: string): EventTarget|null {
|
getGlobalEventTarget(doc: Document, target: string): EventTarget|null {
|
||||||
if (target === 'window') {
|
if (target === 'window') {
|
||||||
return doc.defaultView;
|
return doc.defaultView;
|
||||||
|
|
|
@ -22,6 +22,7 @@ export class ServerEventManagerPlugin /* extends EventManagerPlugin which is pri
|
||||||
return getDOM().onAndCancel(element, eventName, handler);
|
return getDOM().onAndCancel(element, eventName, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @deprecated No longer being used in Ivy code. To be removed in version 14. */
|
||||||
addGlobalEventListener(element: string, eventName: string, handler: Function): Function {
|
addGlobalEventListener(element: string, eventName: string, handler: Function): Function {
|
||||||
const target: HTMLElement = getDOM().getGlobalEventTarget(this.doc, element);
|
const target: HTMLElement = getDOM().getGlobalEventTarget(this.doc, element);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
|
|
Loading…
Reference in New Issue