From fac066ea9f51328619b3acf8ec37882c35cacc31 Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski Date: Tue, 27 Aug 2019 16:15:04 +0200 Subject: [PATCH] perf(ivy): run registerPostOrderHooks in the first template pass only (#32342) PR Close #32342 --- packages/core/src/render3/hooks.ts | 53 +++++++++---------- .../src/render3/instructions/container.ts | 2 +- .../core/src/render3/instructions/element.ts | 9 ++-- .../render3/instructions/element_container.ts | 10 ++-- 4 files changed, 36 insertions(+), 38 deletions(-) diff --git a/packages/core/src/render3/hooks.ts b/packages/core/src/render3/hooks.ts index 8f7c1a4945..4c7c564118 100644 --- a/packages/core/src/render3/hooks.ts +++ b/packages/core/src/render3/hooks.ts @@ -8,6 +8,7 @@ import {assertEqual, assertNotEqual} from '../util/assert'; +import {assertFirstTemplatePass} from './assert'; import {DirectiveDef} from './interfaces/definition'; import {TNode} from './interfaces/node'; import {FLAGS, HookData, InitPhaseState, LView, LViewFlags, PREORDER_HOOK_FLAGS, PreOrderHookFlags, TView} from './interfaces/view'; @@ -35,9 +36,7 @@ import {getCheckNoChangesMode} from './state'; export function registerPreOrderHooks( directiveIndex: number, directiveDef: DirectiveDef, tView: TView, nodeIndex: number, initialPreOrderHooksLength: number, initialPreOrderCheckHooksLength: number): void { - ngDevMode && - assertEqual(tView.firstTemplatePass, true, 'Should only be called on first template pass'); - + ngDevMode && assertFirstTemplatePass(tView); const {onChanges, onInit, doCheck} = directiveDef; if (initialPreOrderHooksLength >= 0 && (!tView.preOrderHooks || initialPreOrderHooksLength === tView.preOrderHooks.length) && @@ -86,35 +85,33 @@ export function registerPreOrderHooks( * @param tNode The TNode whose directives are to be searched for hooks to queue */ export function registerPostOrderHooks(tView: TView, tNode: TNode): void { - if (tView.firstTemplatePass) { - // It's necessary to loop through the directives at elementEnd() (rather than processing in - // directiveCreate) so we can preserve the current hook order. Content, view, and destroy - // hooks for projected components and directives must be called *before* their hosts. - for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) { - const directiveDef = tView.data[i] as DirectiveDef; - if (directiveDef.afterContentInit) { - (tView.contentHooks || (tView.contentHooks = [])).push(-i, directiveDef.afterContentInit); - } + ngDevMode && assertFirstTemplatePass(tView); + // It's necessary to loop through the directives at elementEnd() (rather than processing in + // directiveCreate) so we can preserve the current hook order. Content, view, and destroy + // hooks for projected components and directives must be called *before* their hosts. + for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) { + const directiveDef = tView.data[i] as DirectiveDef; + if (directiveDef.afterContentInit) { + (tView.contentHooks || (tView.contentHooks = [])).push(-i, directiveDef.afterContentInit); + } - if (directiveDef.afterContentChecked) { - (tView.contentHooks || (tView.contentHooks = [])).push(i, directiveDef.afterContentChecked); - (tView.contentCheckHooks || (tView.contentCheckHooks = [ - ])).push(i, directiveDef.afterContentChecked); - } + if (directiveDef.afterContentChecked) { + (tView.contentHooks || (tView.contentHooks = [])).push(i, directiveDef.afterContentChecked); + (tView.contentCheckHooks || (tView.contentCheckHooks = [ + ])).push(i, directiveDef.afterContentChecked); + } - if (directiveDef.afterViewInit) { - (tView.viewHooks || (tView.viewHooks = [])).push(-i, directiveDef.afterViewInit); - } + if (directiveDef.afterViewInit) { + (tView.viewHooks || (tView.viewHooks = [])).push(-i, directiveDef.afterViewInit); + } - if (directiveDef.afterViewChecked) { - (tView.viewHooks || (tView.viewHooks = [])).push(i, directiveDef.afterViewChecked); - (tView.viewCheckHooks || (tView.viewCheckHooks = [ - ])).push(i, directiveDef.afterViewChecked); - } + if (directiveDef.afterViewChecked) { + (tView.viewHooks || (tView.viewHooks = [])).push(i, directiveDef.afterViewChecked); + (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, directiveDef.afterViewChecked); + } - if (directiveDef.onDestroy != null) { - (tView.destroyHooks || (tView.destroyHooks = [])).push(i, directiveDef.onDestroy); - } + if (directiveDef.onDestroy != null) { + (tView.destroyHooks || (tView.destroyHooks = [])).push(i, directiveDef.onDestroy); } } } diff --git a/packages/core/src/render3/instructions/container.ts b/packages/core/src/render3/instructions/container.ts index f2e25ac44d..3684fedae1 100644 --- a/packages/core/src/render3/instructions/container.ts +++ b/packages/core/src/render3/instructions/container.ts @@ -74,6 +74,7 @@ export function ɵɵtemplate( if (tView.firstTemplatePass) { ngDevMode && ngDevMode.firstTemplatePass++; resolveDirectives(tView, lView, tContainerNode, localRefs || null); + registerPostOrderHooks(tView, tContainerNode); const embeddedTView = tContainerNode.tViews = createTView( -1, templateFn, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null, @@ -90,7 +91,6 @@ export function ɵɵtemplate( createDirectivesAndLocals(tView, lView, tContainerNode, localRefExtractor); attachPatchData(getNativeByTNode(tContainerNode, lView), lView); - registerPostOrderHooks(tView, tContainerNode); setIsNotParent(); } diff --git a/packages/core/src/render3/instructions/element.ts b/packages/core/src/render3/instructions/element.ts index 3b6eb3e411..755894002f 100644 --- a/packages/core/src/render3/instructions/element.ts +++ b/packages/core/src/render3/instructions/element.ts @@ -124,12 +124,13 @@ export function ɵɵelementEnd(): void { const lView = getLView(); const tView = lView[TVIEW]; - registerPostOrderHooks(tView, previousOrParentTNode); decreaseElementDepthCount(); - if (tView.firstTemplatePass && tView.queries !== null && - isContentQueryHost(previousOrParentTNode)) { - tView.queries !.elementEnd(previousOrParentTNode); + if (tView.firstTemplatePass) { + registerPostOrderHooks(tView, previousOrParentTNode); + if (isContentQueryHost(previousOrParentTNode)) { + tView.queries !.elementEnd(previousOrParentTNode); + } } if (hasClassInput(tNode) && tNode.classes) { diff --git a/packages/core/src/render3/instructions/element_container.ts b/packages/core/src/render3/instructions/element_container.ts index 2e31723aa9..5c38008487 100644 --- a/packages/core/src/render3/instructions/element_container.ts +++ b/packages/core/src/render3/instructions/element_container.ts @@ -94,11 +94,11 @@ export function ɵɵelementContainerEnd(): void { ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.ElementContainer); - registerPostOrderHooks(tView, previousOrParentTNode); - - if (tView.firstTemplatePass && tView.queries !== null && - isContentQueryHost(previousOrParentTNode)) { - tView.queries.elementEnd(previousOrParentTNode); + if (tView.firstTemplatePass) { + registerPostOrderHooks(tView, previousOrParentTNode); + if (isContentQueryHost(previousOrParentTNode)) { + tView.queries !.elementEnd(previousOrParentTNode); + } } }