perf(ivy): attempt to coalesce listeners only in presence of directives (#29859)

PR Close #29859
This commit is contained in:
Pawel Kozlowski 2019-04-12 10:34:38 +02:00 committed by Alex Rickabaugh
parent d1d0f4a1ad
commit 6a1441f727
3 changed files with 18 additions and 4 deletions

View File

@ -14,7 +14,7 @@ import {GlobalTargetResolver, RElement, Renderer3, isProceduralRenderer} from '.
import {CLEANUP, FLAGS, LView, LViewFlags, RENDERER, TVIEW} from '../interfaces/view'; import {CLEANUP, FLAGS, LView, LViewFlags, RENDERER, TVIEW} from '../interfaces/view';
import {assertNodeOfPossibleTypes} from '../node_assert'; import {assertNodeOfPossibleTypes} from '../node_assert';
import {getLView, getPreviousOrParentTNode} from '../state'; import {getLView, getPreviousOrParentTNode} from '../state';
import {getComponentViewByIndex, getNativeByTNode, unwrapRNode} from '../util/view_utils'; import {getComponentViewByIndex, getNativeByTNode, hasDirectives, unwrapRNode} from '../util/view_utils';
import {BindingDirection, generatePropertyAliases, getCleanup, handleError, loadComponentRenderer, markViewDirty} from './shared'; import {BindingDirection, generatePropertyAliases, getCleanup, handleError, loadComponentRenderer, markViewDirty} from './shared';
/** /**
@ -132,12 +132,16 @@ function listenerInternal(
// In order to have just one native event handler in presence of multiple handler functions, // In order to have just one native event handler in presence of multiple handler functions,
// we just register a first handler function as a native event listener and then chain // we just register a first handler function as a native event listener and then chain
// (coalesce) other handler functions on top of the first native handler function. // (coalesce) other handler functions on top of the first native handler function.
// let existingListener = null;
// Please note that the coalescing described here doesn't happen for events specifying an // Please note that the coalescing described here doesn't happen for events specifying an
// alternative target (ex. (document:click)) - this is to keep backward compatibility with the // alternative target (ex. (document:click)) - this is to keep backward compatibility with the
// view engine. // view engine.
const existingListener = // Also, we don't have to search for existing listeners is there are no directives
eventTargetResolver ? null : findExistingListener(lView, eventName, tNode.index); // matching on a given node as we can't register multiple event handlers for the same event in
// a template (this would mean having duplicate attributes).
if (!eventTargetResolver && hasDirectives(tNode)) {
existingListener = findExistingListener(lView, eventName, tNode.index);
}
if (existingListener !== null) { if (existingListener !== null) {
// Attach a new listener at the head of the coalesced listeners list. // Attach a new listener at the head of the coalesced listeners list.
(<any>listenerFn).__ngNextListenerFn__ = (<any>existingListener).__ngNextListenerFn__; (<any>listenerFn).__ngNextListenerFn__ = (<any>existingListener).__ngNextListenerFn__;

View File

@ -131,6 +131,13 @@ export function getNativeByTNode(tNode: TNode, hostView: LView): RNode {
return unwrapRNode(hostView[tNode.index]); return unwrapRNode(hostView[tNode.index]);
} }
/**
* A helper function that returns `true` if a given `TNode` has any matching directives.
*/
export function hasDirectives(tNode: TNode): boolean {
return tNode.directiveEnd > tNode.directiveStart;
}
export function getTNode(index: number, view: LView): TNode { export function getTNode(index: number, view: LView): TNode {
ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode'); ngDevMode && assertGreaterThan(index, -1, 'wrong index for TNode');
ngDevMode && assertLessThan(index, view[TVIEW].data.length, 'wrong index for TNode'); ngDevMode && assertLessThan(index, view[TVIEW].data.length, 'wrong index for TNode');

View File

@ -848,6 +848,9 @@
{ {
"name": "hasClassInput" "name": "hasClassInput"
}, },
{
"name": "hasDirectives"
},
{ {
"name": "hasParentInjector" "name": "hasParentInjector"
}, },