perf(ivy): run registerPostOrderHooks in the first template pass only (#32342)

PR Close #32342
This commit is contained in:
Pawel Kozlowski 2019-08-27 16:15:04 +02:00 committed by Miško Hevery
parent 85864ed9f7
commit fac066ea9f
4 changed files with 36 additions and 38 deletions

View File

@ -8,6 +8,7 @@
import {assertEqual, assertNotEqual} from '../util/assert'; import {assertEqual, assertNotEqual} from '../util/assert';
import {assertFirstTemplatePass} from './assert';
import {DirectiveDef} from './interfaces/definition'; import {DirectiveDef} from './interfaces/definition';
import {TNode} from './interfaces/node'; import {TNode} from './interfaces/node';
import {FLAGS, HookData, InitPhaseState, LView, LViewFlags, PREORDER_HOOK_FLAGS, PreOrderHookFlags, TView} from './interfaces/view'; 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( export function registerPreOrderHooks(
directiveIndex: number, directiveDef: DirectiveDef<any>, tView: TView, nodeIndex: number, directiveIndex: number, directiveDef: DirectiveDef<any>, tView: TView, nodeIndex: number,
initialPreOrderHooksLength: number, initialPreOrderCheckHooksLength: number): void { initialPreOrderHooksLength: number, initialPreOrderCheckHooksLength: number): void {
ngDevMode && ngDevMode && assertFirstTemplatePass(tView);
assertEqual(tView.firstTemplatePass, true, 'Should only be called on first template pass');
const {onChanges, onInit, doCheck} = directiveDef; const {onChanges, onInit, doCheck} = directiveDef;
if (initialPreOrderHooksLength >= 0 && if (initialPreOrderHooksLength >= 0 &&
(!tView.preOrderHooks || initialPreOrderHooksLength === tView.preOrderHooks.length) && (!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 * @param tNode The TNode whose directives are to be searched for hooks to queue
*/ */
export function registerPostOrderHooks(tView: TView, tNode: TNode): void { export function registerPostOrderHooks(tView: TView, tNode: TNode): void {
if (tView.firstTemplatePass) { ngDevMode && assertFirstTemplatePass(tView);
// It's necessary to loop through the directives at elementEnd() (rather than processing in // 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 // 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. // hooks for projected components and directives must be called *before* their hosts.
for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) { for (let i = tNode.directiveStart, end = tNode.directiveEnd; i < end; i++) {
const directiveDef = tView.data[i] as DirectiveDef<any>; const directiveDef = tView.data[i] as DirectiveDef<any>;
if (directiveDef.afterContentInit) { if (directiveDef.afterContentInit) {
(tView.contentHooks || (tView.contentHooks = [])).push(-i, directiveDef.afterContentInit); (tView.contentHooks || (tView.contentHooks = [])).push(-i, directiveDef.afterContentInit);
} }
if (directiveDef.afterContentChecked) { if (directiveDef.afterContentChecked) {
(tView.contentHooks || (tView.contentHooks = [])).push(i, directiveDef.afterContentChecked); (tView.contentHooks || (tView.contentHooks = [])).push(i, directiveDef.afterContentChecked);
(tView.contentCheckHooks || (tView.contentCheckHooks = [ (tView.contentCheckHooks || (tView.contentCheckHooks = [
])).push(i, directiveDef.afterContentChecked); ])).push(i, directiveDef.afterContentChecked);
} }
if (directiveDef.afterViewInit) { if (directiveDef.afterViewInit) {
(tView.viewHooks || (tView.viewHooks = [])).push(-i, directiveDef.afterViewInit); (tView.viewHooks || (tView.viewHooks = [])).push(-i, directiveDef.afterViewInit);
} }
if (directiveDef.afterViewChecked) { if (directiveDef.afterViewChecked) {
(tView.viewHooks || (tView.viewHooks = [])).push(i, directiveDef.afterViewChecked); (tView.viewHooks || (tView.viewHooks = [])).push(i, directiveDef.afterViewChecked);
(tView.viewCheckHooks || (tView.viewCheckHooks = [ (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, directiveDef.afterViewChecked);
])).push(i, directiveDef.afterViewChecked); }
}
if (directiveDef.onDestroy != null) { if (directiveDef.onDestroy != null) {
(tView.destroyHooks || (tView.destroyHooks = [])).push(i, directiveDef.onDestroy); (tView.destroyHooks || (tView.destroyHooks = [])).push(i, directiveDef.onDestroy);
}
} }
} }
} }

View File

@ -74,6 +74,7 @@ export function ɵɵtemplate(
if (tView.firstTemplatePass) { if (tView.firstTemplatePass) {
ngDevMode && ngDevMode.firstTemplatePass++; ngDevMode && ngDevMode.firstTemplatePass++;
resolveDirectives(tView, lView, tContainerNode, localRefs || null); resolveDirectives(tView, lView, tContainerNode, localRefs || null);
registerPostOrderHooks(tView, tContainerNode);
const embeddedTView = tContainerNode.tViews = createTView( const embeddedTView = tContainerNode.tViews = createTView(
-1, templateFn, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null, -1, templateFn, consts, vars, tView.directiveRegistry, tView.pipeRegistry, null,
@ -90,7 +91,6 @@ export function ɵɵtemplate(
createDirectivesAndLocals(tView, lView, tContainerNode, localRefExtractor); createDirectivesAndLocals(tView, lView, tContainerNode, localRefExtractor);
attachPatchData(getNativeByTNode(tContainerNode, lView), lView); attachPatchData(getNativeByTNode(tContainerNode, lView), lView);
registerPostOrderHooks(tView, tContainerNode);
setIsNotParent(); setIsNotParent();
} }

View File

@ -124,12 +124,13 @@ export function ɵɵelementEnd(): void {
const lView = getLView(); const lView = getLView();
const tView = lView[TVIEW]; const tView = lView[TVIEW];
registerPostOrderHooks(tView, previousOrParentTNode);
decreaseElementDepthCount(); decreaseElementDepthCount();
if (tView.firstTemplatePass && tView.queries !== null && if (tView.firstTemplatePass) {
isContentQueryHost(previousOrParentTNode)) { registerPostOrderHooks(tView, previousOrParentTNode);
tView.queries !.elementEnd(previousOrParentTNode); if (isContentQueryHost(previousOrParentTNode)) {
tView.queries !.elementEnd(previousOrParentTNode);
}
} }
if (hasClassInput(tNode) && tNode.classes) { if (hasClassInput(tNode) && tNode.classes) {

View File

@ -94,11 +94,11 @@ export function ɵɵelementContainerEnd(): void {
ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.ElementContainer); ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.ElementContainer);
registerPostOrderHooks(tView, previousOrParentTNode); if (tView.firstTemplatePass) {
registerPostOrderHooks(tView, previousOrParentTNode);
if (tView.firstTemplatePass && tView.queries !== null && if (isContentQueryHost(previousOrParentTNode)) {
isContentQueryHost(previousOrParentTNode)) { tView.queries !.elementEnd(previousOrParentTNode);
tView.queries.elementEnd(previousOrParentTNode); }
} }
} }