refactor(ivy): replace LView.child with TView.childIndex lookup (#24211)

PR Close #24211
This commit is contained in:
Kara Erickson 2018-05-30 13:43:14 -07:00 committed by Victor Berchet
parent 6a663a4073
commit 7e3f8f77a9
6 changed files with 53 additions and 29 deletions

View File

@ -590,7 +590,7 @@ export function getOrCreateContainerRef(di: LInjector): viewEngine_ViewContainer
lContainerNode.tNode = hostTNode.dynamicContainerNode;
vcRefHost.dynamicLContainerNode = lContainerNode;
addToViewTree(vcRefHost.view, lContainer);
addToViewTree(vcRefHost.view, hostTNode.index as number, lContainer);
di.viewContainerRef = new ViewContainerRef(lContainerNode);
}

View File

@ -17,7 +17,7 @@ import {CurrentMatchesList, LView, LViewFlags, LifecycleStage, RootContext, TDat
import {AttributeMarker, TAttributes, LContainerNode, LElementNode, LNode, TNodeType, TNodeFlags, LProjectionNode, LTextNode, LViewNode, TNode, TContainerNode, InitialInputData, InitialInputs, PropertyAliases, PropertyAliasValue, TElementNode,} from './interfaces/node';
import {assertNodeType} from './node_assert';
import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode, getNextLNode, getChildLNode, getParentLNode} from './node_manipulation';
import {appendChild, insertView, appendProjectedNode, removeView, canInsertNativeNode, createTextNode, getNextLNode, getChildLNode, getParentLNode, getLViewChild} from './node_manipulation';
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefList, DirectiveDefListOrFactory, PipeDefList, PipeDefListOrFactory, RenderFlags} from './interfaces/definition';
import {RElement, RText, Renderer3, RendererFactory3, ProceduralRenderer3, RendererStyleFlags3, isProceduralRenderer} from './interfaces/renderer';
@ -314,7 +314,6 @@ export function createLView<T>(
tView: tView,
cleanup: null,
renderer: renderer,
child: null,
tail: null,
next: null,
bindingStartIndex: -1,
@ -802,6 +801,7 @@ export function createTView(
return {
node: null !,
data: [],
childIndex: -1, // Children set in addToViewTree(), if any
directives: null,
firstTemplatePass: true,
initHooks: null,
@ -1329,11 +1329,12 @@ function addComponentLogic<T>(index: number, instance: T, def: ComponentDef<T>):
// Only component views should be added to the view tree directly. Embedded views are
// accessed through their containers because they may be removed / re-added later.
const hostView = addToViewTree(
currentView, createLView(
-1, rendererFactory.createRenderer(
previousOrParentNode.native as RElement, def.rendererType),
tView, null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways,
getCurrentSanitizer()));
currentView, previousOrParentNode.tNode.index as number,
createLView(
-1,
rendererFactory.createRenderer(previousOrParentNode.native as RElement, def.rendererType),
tView, null, null, def.onPush ? LViewFlags.Dirty : LViewFlags.CheckAlways,
getCurrentSanitizer()));
// We need to set the host node/data here because when the component LNode was created,
// we didn't yet know it was a component (just an element).
@ -1512,7 +1513,7 @@ export function container(
// Containers are added to the current view tree instead of their embedded views
// because views can be removed and re-inserted.
addToViewTree(currentView, node.data);
addToViewTree(currentView, index, node.data);
createDirectivesAndLocals(localRefs);
isParent = false;
@ -1574,7 +1575,7 @@ export function containerRefreshEnd(): void {
}
function refreshDynamicChildren() {
for (let current = currentView.child; current !== null; current = current.next) {
for (let current = getLViewChild(currentView); current !== null; current = current.next) {
// Note: current can be a LView or a LContainer, but here we are only interested in LContainer.
// The distinction is made because nextIndex and views do not exist on LView.
if (isLContainer(current)) {
@ -1921,11 +1922,18 @@ function findComponentHost(lView: LView): LElementNode {
* and call onDestroy callbacks.
*
* @param currentView The view where LView or LContainer should be added
* @param hostIndex Index of the view's host node in data[]
* @param state The LView or LContainer to add to the view tree
* @returns The state passed in
*/
export function addToViewTree<T extends LView|LContainer>(currentView: LView, state: T): T {
currentView.tail ? (currentView.tail.next = state) : (currentView.child = state);
export function addToViewTree<T extends LView|LContainer>(
currentView: LView, hostIndex: number, state: T): T {
// TODO(kara): move next and tail properties off of LView
if (currentView.tail) {
currentView.tail.next = state;
} else if (firstTemplatePass) {
currentView.tView.childIndex = hostIndex;
}
currentView.tail = state;
return state;
}

View File

@ -112,17 +112,6 @@ export interface LView {
*/
lifecycleStage: LifecycleStage;
/**
* The first LView or LContainer beneath this LView in the hierarchy.
*
* Necessary to store this so views can traverse through their nested views
* to remove listeners and call onDestroy callbacks.
*
* For embedded views, we store the LContainer rather than the first ViewState
* to avoid managing splicing when views are added/removed.
*/
child: LView|LContainer|null;
/**
* The last LView or LContainer beneath this LView in the hierarchy.
*
@ -222,8 +211,8 @@ export const enum LViewFlags {
/** Interface necessary to work with view tree traversal */
export interface LViewOrLContainer {
next: LView|LContainer|null;
child?: LView|LContainer|null;
views?: LViewNode[];
tView?: TView;
parent: LView|null;
}
@ -251,6 +240,18 @@ export interface TView {
/** Static data equivalent of LView.data[]. Contains TNodes. */
data: TData;
/**
* Index of the host node of the first LView or LContainer beneath this LView in
* the hierarchy.
*
* Necessary to store this so views can traverse through their nested views
* to remove listeners and call onDestroy callbacks.
*
* For embedded views, we store the index of an LContainer's host rather than the first
* LView to avoid managing splicing when views are added/removed.
*/
childIndex: number;
/**
* Selector matches for a node are temporarily cached on the TView so the
* DI system can eagerly instantiate directives on the same node if they are

View File

@ -261,19 +261,19 @@ export function addRemoveViewFromContainer(
* @param rootView The view to destroy
*/
export function destroyViewTree(rootView: LView): void {
// A view to cleanup doesn't have children so we should not try to descend down the view tree.
if (!rootView.child) {
// If the view has no children, we can clean it up and return early.
if (rootView.tView.childIndex === -1) {
return cleanUpView(rootView);
}
let viewOrContainer: LViewOrLContainer|null = rootView.child;
let viewOrContainer: LViewOrLContainer|null = getLViewChild(rootView);
while (viewOrContainer) {
let next: LViewOrLContainer|null = null;
if (viewOrContainer.views && viewOrContainer.views.length) {
next = viewOrContainer.views[0].data;
} else if (viewOrContainer.child) {
next = viewOrContainer.child;
} else if (viewOrContainer.tView && viewOrContainer.tView.childIndex > -1) {
next = getLViewChild(viewOrContainer as LView);
} else if (viewOrContainer.next) {
// Only move to the side and clean if operating below rootView -
// otherwise we would start cleaning up sibling views of the rootView.
@ -383,6 +383,15 @@ export function removeView(container: LContainerNode, removeIndex: number): LVie
return viewNode;
}
/** Gets the child of the given LView */
export function getLViewChild(view: LView): LView|LContainer|null {
if (view.tView.childIndex === -1) return null;
const hostNode: LElementNode|LContainerNode = view.data[view.tView.childIndex];
return hostNode.data ? hostNode.data : (hostNode.dynamicLContainerNode as LContainerNode).data;
}
/**
* Determines which LViewOrLContainer to jump to when traversing back up the
* tree in destroyViewTree.

View File

@ -107,6 +107,9 @@
{
"name": "getDirectiveInstance"
},
{
"name": "getLViewChild"
},
{
"name": "getOrCreateTView"
},

View File

@ -389,6 +389,9 @@
{
"name": "getDirectiveInstance"
},
{
"name": "getLViewChild"
},
{
"name": "getNextLNode"
},