From 02483a01ad08658c5d10d507f90c75c40c10d5db Mon Sep 17 00:00:00 2001 From: Jason Aden Date: Mon, 29 Jan 2018 21:42:37 -0800 Subject: [PATCH] Revert: "refactor(ivy): save check methods separately" This reverts commit 278889c7b420e530834c457f82a54e33a846a828. --- packages/core/src/render3/hooks.ts | 78 +++++++++++++------ packages/core/src/render3/index.ts | 2 + packages/core/src/render3/instructions.ts | 15 ++-- packages/core/src/render3/interfaces/view.ts | 43 ++-------- .../core/src/render3/node_manipulation.ts | 8 +- 5 files changed, 75 insertions(+), 71 deletions(-) diff --git a/packages/core/src/render3/hooks.ts b/packages/core/src/render3/hooks.ts index 89b36d80cd..be76049088 100644 --- a/packages/core/src/render3/hooks.ts +++ b/packages/core/src/render3/hooks.ts @@ -10,6 +10,20 @@ import {DirectiveDef} from './interfaces/definition'; import {LNodeFlags} from './interfaces/node'; import {HookData, LView, LifecycleStage, TView} from './interfaces/view'; + + +/** Constants used by lifecycle hooks to determine when and how a hook should be called. */ +export const enum LifecycleHook { + ON_INIT = 0b00, + ON_CHECK = 0b01, + + /* Mask used to get the type of the lifecycle hook from flags in hook queue */ + TYPE_MASK = 0b00000000000000000000000000000001, + + /* Shift needed to get directive index from flags in hook queue */ + INDX_SHIFT = 1 +} + /** * If this is the first template pass, any ngOnInit or ngDoCheck hooks will be queued into * TView.initHooks during directiveCreate. @@ -26,12 +40,11 @@ export function queueInitHooks( index: number, onInit: (() => void) | null, doCheck: (() => void) | null, tView: TView): void { if (tView.firstTemplatePass === true) { if (onInit != null) { - (tView.initHooks || (tView.initHooks = [])).push(index, onInit); + (tView.initHooks || (tView.initHooks = [])).push(getInitFlags(index), onInit); } if (doCheck != null) { - (tView.initHooks || (tView.initHooks = [])).push(index, doCheck); - (tView.checkHooks || (tView.checkHooks = [])).push(index, doCheck); + (tView.initHooks || (tView.initHooks = [])).push(getCheckFlags(index), doCheck); } } } @@ -61,24 +74,23 @@ export function queueLifecycleHooks(flags: number, currentView: LView): void { /** Queues afterContentInit and afterContentChecked hooks on TView */ function queueContentHooks(def: DirectiveDef, tView: TView, i: number): void { if (def.afterContentInit != null) { - (tView.contentHooks || (tView.contentHooks = [])).push(i, def.afterContentInit); + (tView.contentHooks || (tView.contentHooks = [])).push(getInitFlags(i), def.afterContentInit); } if (def.afterContentChecked != null) { - (tView.contentHooks || (tView.contentHooks = [])).push(i, def.afterContentChecked); - (tView.contentCheckHooks || (tView.contentCheckHooks = [])).push(i, def.afterContentChecked); + (tView.contentHooks || (tView.contentHooks = [ + ])).push(getCheckFlags(i), def.afterContentChecked); } } /** Queues afterViewInit and afterViewChecked hooks on TView */ function queueViewHooks(def: DirectiveDef, tView: TView, i: number): void { if (def.afterViewInit != null) { - (tView.viewHooks || (tView.viewHooks = [])).push(i, def.afterViewInit); + (tView.viewHooks || (tView.viewHooks = [])).push(getInitFlags(i), def.afterViewInit); } if (def.afterViewChecked != null) { - (tView.viewHooks || (tView.viewHooks = [])).push(i, def.afterViewChecked); - (tView.viewCheckHooks || (tView.viewCheckHooks = [])).push(i, def.afterViewChecked); + (tView.viewHooks || (tView.viewHooks = [])).push(getCheckFlags(i), def.afterViewChecked); } } @@ -89,14 +101,26 @@ function queueDestroyHooks(def: DirectiveDef, tView: TView, i: number): voi } } +/** Generates flags for init-only hooks */ +function getInitFlags(index: number): number { + return index << LifecycleHook.INDX_SHIFT; +} + +/** Generates flags for hooks called every change detection run */ +function getCheckFlags(index: number): number { + return (index << LifecycleHook.INDX_SHIFT) | LifecycleHook.ON_CHECK; +} + /** * Calls onInit and doCheck calls if they haven't already been called. * * @param currentView The current view */ -export function executeInitHooks(currentView: LView, tView: TView, creationMode: boolean): void { - if (currentView.lifecycleStage === LifecycleStage.INIT) { - executeHooks(currentView.data, tView.initHooks, tView.checkHooks, creationMode); +export function executeInitHooks(currentView: LView): void { + const initHooks = currentView.tView.initHooks; + + if (currentView.lifecycleStage === LifecycleStage.INIT && initHooks != null) { + executeLifecycleHooks(currentView, initHooks); currentView.lifecycleStage = LifecycleStage.CONTENT_INIT; } } @@ -107,9 +131,11 @@ export function executeInitHooks(currentView: LView, tView: TView, creationMode: * * @param currentView The current view */ -export function executeContentHooks(currentView: LView, tView: TView, creationMode: boolean): void { - if (currentView.lifecycleStage < LifecycleStage.VIEW_INIT) { - executeHooks(currentView.data, tView.contentHooks, tView.contentCheckHooks, creationMode); +export function executeContentHooks(currentView: LView): void { + const contentHooks = currentView.tView.contentHooks; + + if (currentView.lifecycleStage < LifecycleStage.VIEW_INIT && contentHooks != null) { + executeLifecycleHooks(currentView, contentHooks); currentView.lifecycleStage = LifecycleStage.VIEW_INIT; } } @@ -119,12 +145,11 @@ export function executeContentHooks(currentView: LView, tView: TView, creationMo * * @param currentView The current view */ -export function executeHooks( - data: any[], allHooks: HookData | null, checkHooks: HookData | null, - creationMode: boolean): void { - const hooksToCall = creationMode ? allHooks : checkHooks; - if (hooksToCall != null) { - callHooks(data, hooksToCall); +export function executeViewHooks(currentView: LView): void { + const viewHooks = currentView.tView.viewHooks; + + if (viewHooks != null) { + executeLifecycleHooks(currentView, viewHooks); } } @@ -135,8 +160,15 @@ export function executeHooks( * @param currentView The current view * @param arr The array in which the hooks are found */ -export function callHooks(data: any[], arr: HookData): void { +function executeLifecycleHooks(currentView: LView, arr: HookData): void { + const data = currentView.data; + const creationMode = currentView.creationMode; + for (let i = 0; i < arr.length; i += 2) { - (arr[i | 1] as() => void).call(data[arr[i] as number]); + const flags = arr[i] as number; + const initOnly = (flags & LifecycleHook.TYPE_MASK) === LifecycleHook.ON_INIT; + if (initOnly === false || creationMode) { + (arr[i | 1] as() => void).call(data[flags >> LifecycleHook.INDX_SHIFT]); + } } } diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index 11c3200fc5..af03107749 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -70,6 +70,8 @@ export { queryRefresh as qR, } from './query'; +export {LifecycleHook} from './hooks'; + // clang-format on export { diff --git a/packages/core/src/render3/instructions.ts b/packages/core/src/render3/instructions.ts index 149ae89e6b..a156f6fcce 100644 --- a/packages/core/src/render3/instructions.ts +++ b/packages/core/src/render3/instructions.ts @@ -21,7 +21,7 @@ import {isNodeMatchingSelector} from './node_selector_matcher'; import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType} from './interfaces/definition'; import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, ObjectOrientedRenderer3, RendererStyleFlags3} from './interfaces/renderer'; import {isDifferent, stringify} from './util'; -import {executeHooks, executeContentHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks'; +import {executeViewHooks, executeContentHooks, queueLifecycleHooks, queueInitHooks, executeInitHooks} from './hooks'; /** @@ -151,9 +151,7 @@ export function enterView(newView: LView, host: LElementNode | LViewNode | null) * the direction of traversal (up or down the view tree) a bit clearer. */ export function leaveView(newView: LView): void { - executeHooks( - currentView.data, currentView.tView.viewHooks, currentView.tView.viewCheckHooks, - creationMode); + executeViewHooks(currentView); currentView.creationMode = false; currentView.lifecycleStage = LifecycleStage.INIT; currentView.tView.firstTemplatePass = false; @@ -488,11 +486,8 @@ export function createTView(): TView { data: [], firstTemplatePass: true, initHooks: null, - checkHooks: null, contentHooks: null, - contentCheckHooks: null, viewHooks: null, - viewCheckHooks: null, destroyHooks: null }; } @@ -1049,7 +1044,7 @@ export function containerRefreshStart(index: number): void { // We need to execute init hooks here so ngOnInit hooks are called in top level views // before they are called in embedded views (for backwards compatibility). - executeInitHooks(currentView, currentView.tView, creationMode); + executeInitHooks(currentView); } /** @@ -1180,8 +1175,8 @@ export function viewEnd(): void { * @param elementIndex */ export function componentRefresh(directiveIndex: number, elementIndex: number): void { - executeInitHooks(currentView, currentView.tView, creationMode); - executeContentHooks(currentView, currentView.tView, creationMode); + executeInitHooks(currentView); + executeContentHooks(currentView); const template = (tData[directiveIndex] as ComponentDef).template; if (template != null) { ngDevMode && assertDataInRange(elementIndex); diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index 2cba73935e..3dcc56def9 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -200,58 +200,31 @@ export interface TView { firstTemplatePass: boolean; /** - * Array of ngOnInit and ngDoCheck hooks that should be executed for this view in - * creation mode. + * Array of ngOnInit and ngDoCheck hooks that should be executed for this view. * - * Even indices: Directive index + * Even indices: Flags (1st bit: hook type, remaining: directive index) * Odd indices: Hook function */ initHooks: HookData|null; /** - * Array of ngDoCheck hooks that should be executed for this view in update mode. + * Array of ngAfterContentInit and ngAfterContentChecked hooks that should be executed for + * this view. * - * Even indices: Directive index - * Odd indices: Hook function - */ - checkHooks: HookData|null; - - /** - * Array of ngAfterContentInit and ngAfterContentChecked hooks that should be executed - * for this view in creation mode. - * - * Even indices: Directive index + * Even indices: Flags (1st bit: hook type, remaining: directive index) * Odd indices: Hook function */ contentHooks: HookData|null; - /** - * Array of ngAfterContentChecked hooks that should be executed for this view in update - * mode. - * - * Even indices: Directive index - * Odd indices: Hook function - */ - contentCheckHooks: HookData|null; - /** * Array of ngAfterViewInit and ngAfterViewChecked hooks that should be executed for - * this view in creation mode. + * this view. * - * Even indices: Directive index + * Even indices: Flags (1st bit: hook type, remaining: directive index) * Odd indices: Hook function */ viewHooks: HookData|null; - /** - * Array of ngAfterViewChecked hooks that should be executed for this view in - * update mode. - * - * Even indices: Directive index - * Odd indices: Hook function - */ - viewCheckHooks: HookData|null; - /** * Array of ngOnDestroy hooks that should be executed when this view is destroyed. * @@ -264,7 +237,7 @@ export interface TView { /** * Array of hooks that should be executed for a view and their directive indices. * - * Even indices: Directive index + * Even indices: Flags (1st bit: hook type, remaining: directive index) * Odd indices: Hook function */ export type HookData = (number | (() => void))[]; diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index 427a898c10..d276815e07 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -6,8 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {assertNotNull} from './assert'; -import {callHooks} from './hooks'; +import {assertNotEqual, assertNotNull} from './assert'; import {LContainer, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; import {LContainerNode, LElementNode, LNode, LNodeFlags, LProjectionNode, LTextNode, LViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'; @@ -386,7 +385,10 @@ function executeOnDestroys(view: LView): void { const tView = view.tView; let destroyHooks: HookData|null; if (tView != null && (destroyHooks = tView.destroyHooks) != null) { - callHooks(view.data, destroyHooks); + for (let i = 0; i < destroyHooks.length; i += 2) { + const instance = view.data[destroyHooks[i] as number]; + (destroyHooks[i | 1] as() => void).call(instance); + } } }