refactor(core): view engine, refactor runtime data

Structure in a better way, in preparation for queries.
This commit is contained in:
Tobias Bosch 2017-01-23 10:23:44 -08:00 committed by Victor Berchet
parent 05b2b49711
commit fc8694ed11
11 changed files with 74 additions and 66 deletions

View File

@ -97,7 +97,7 @@ export function elementDef(
}
export function createElement(view: ViewData, renderHost: any, def: NodeDef): NodeData {
const parentNode = def.parent != null ? view.nodes[def.parent].renderNode : renderHost;
const parentNode = def.parent != null ? view.nodes[def.parent].elementOrText.node : renderHost;
const elDef = def.element;
let el: any;
if (view.renderer) {
@ -150,10 +150,10 @@ export function createElement(view: ViewData, renderHost: any, def: NodeDef): No
}
}
return {
renderNode: el,
elementOrText:
{node: el, embeddedViews: (def.flags & NodeFlags.HasEmbeddedViews) ? [] : undefined},
provider: undefined,
embeddedViews: (def.flags & NodeFlags.HasEmbeddedViews) ? [] : undefined,
componentView: undefined
pureExpression: undefined,
};
}
@ -213,7 +213,7 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu
const binding = def.bindings[bindingIdx];
const name = binding.name;
const renderNode = view.nodes[def.index].renderNode;
const renderNode = view.nodes[def.index].elementOrText.node;
switch (binding.type) {
case BindingType.ElementAttribute:
setElementAttribute(view, binding, renderNode, name, value);

View File

@ -102,16 +102,16 @@ export function createProvider(view: ViewData, def: NodeDef, componentView: View
}
}
return {
renderNode: undefined,
provider,
embeddedViews: undefined, componentView,
elementOrText: undefined,
provider: {instance: provider, componentView: componentView},
pureExpression: undefined,
};
}
export function checkAndUpdateProviderInline(
view: ViewData, def: NodeDef, v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
v7: any, v8: any, v9: any) {
const provider = view.nodes[def.index].provider;
const provider = view.nodes[def.index].provider.instance;
let changes: SimpleChanges;
// Note: fallthrough is intended!
switch (def.bindings.length) {
@ -148,7 +148,7 @@ export function checkAndUpdateProviderInline(
}
export function checkAndUpdateProviderDynamic(view: ViewData, def: NodeDef, values: any[]) {
const provider = view.nodes[def.index].provider;
const provider = view.nodes[def.index].provider.instance;
let changes: SimpleChanges;
for (let i = 0; i < values.length; i++) {
changes = checkAndUpdateProp(view, provider, def, i, values[i], changes);
@ -217,7 +217,7 @@ export function resolveDep(
return Injector.NULL.get(depDef.token, notFoundValue);
}
case ElementRefTokenKey:
return new ElementRef(view.nodes[elIndex].renderNode);
return new ElementRef(view.nodes[elIndex].elementOrText.node);
case ViewContainerRefTokenKey:
return view.services.createViewContainerRef(view.nodes[elIndex]);
case TemplateRefTokenKey:
@ -225,7 +225,7 @@ export function resolveDep(
default:
const providerIndex = elDef.providerIndices[tokenKey];
if (providerIndex != null) {
return view.nodes[providerIndex].provider;
return view.nodes[providerIndex].provider.instance;
}
}
elIndex = view.parentIndex;
@ -255,7 +255,7 @@ function checkAndUpdateProp(
if (view.def.flags & ViewFlags.LogBindingUpdate) {
setBindingDebugInfo(
view.renderer, view.nodes[def.parent].renderNode, binding.nonMinifiedName, value);
view.renderer, view.nodes[def.parent].elementOrText.node, binding.nonMinifiedName, value);
}
if (change) {
changes = changes || {};
@ -276,7 +276,7 @@ export function callLifecycleHooksChildrenFirst(view: ViewData, lifecycles: Node
const nodeIndex = nodeDef.index;
if (nodeDef.flags & lifecycles) {
// a leaf
callProviderLifecycles(view.nodes[nodeIndex].provider, nodeDef.flags & lifecycles);
callProviderLifecycles(view.nodes[nodeIndex].provider.instance, nodeDef.flags & lifecycles);
} else if ((nodeDef.childFlags & lifecycles) === 0) {
// a parent with leafs
// no child matches one of the lifecycles,

View File

@ -7,7 +7,7 @@
*/
import {resolveDep, tokenKey} from './provider';
import {BindingDef, BindingType, DepDef, DepFlags, NodeData, NodeDef, NodeType, PureExpressionData, PureExpressionType, ViewData} from './types';
import {BindingDef, BindingType, DepDef, DepFlags, NodeData, NodeDef, NodeType, ProviderData, PureExpressionType, ViewData} from './types';
import {checkAndUpdateBinding} from './util';
export function purePipeDef(pipeToken: any, argCount: number): NodeDef {
@ -62,13 +62,7 @@ export function createPureExpression(view: ViewData, def: NodeDef): NodeData {
const pipe = def.pureExpression.pipeDep ?
resolveDep(view, def.parent, def.pureExpression.pipeDep) :
undefined;
const data: PureExpressionData = {value: undefined, pipe: pipe};
return {
renderNode: undefined,
provider: data,
embeddedViews: undefined,
componentView: undefined
};
return {elementOrText: undefined, provider: undefined, pureExpression: {value: undefined, pipe}};
}
export function checkAndUpdatePureExpressionInline(
@ -101,7 +95,7 @@ export function checkAndUpdatePureExpressionInline(
}
if (changed) {
const data: PureExpressionData = view.nodes[def.index].provider;
const data = view.nodes[def.index].pureExpression;
let value: any;
switch (def.pureExpression.type) {
case PureExpressionType.Array:
@ -206,7 +200,7 @@ export function checkAndUpdatePureExpressionDynamic(view: ViewData, def: NodeDef
}
}
if (changed) {
const data: PureExpressionData = view.nodes[def.index].provider;
const data = view.nodes[def.index].pureExpression;
let value: any;
switch (def.pureExpression.type) {
case PureExpressionType.Array:

View File

@ -48,16 +48,18 @@ class ViewContainerRef_ implements ViewContainerRef {
get parentInjector(): Injector { return <Injector>unimplemented(); }
clear(): void {
const len = this._data.embeddedViews.length;
const len = this._data.elementOrText.embeddedViews.length;
for (let i = len - 1; i >= 0; i--) {
const view = detachEmbeddedView(this._data, i);
destroyView(view);
}
}
get(index: number): ViewRef { return new ViewRef_(this._data.embeddedViews[index]); }
get(index: number): ViewRef {
return new ViewRef_(this._data.elementOrText.embeddedViews[index]);
}
get length(): number { return this._data.embeddedViews.length; };
get length(): number { return this._data.elementOrText.embeddedViews.length; };
createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number):
EmbeddedViewRef<C> {
@ -81,7 +83,7 @@ class ViewContainerRef_ implements ViewContainerRef {
move(viewRef: ViewRef, currentIndex: number): ViewRef { return unimplemented(); }
indexOf(viewRef: ViewRef): number {
return this._data.embeddedViews.indexOf((<ViewRef_>viewRef)._view);
return this._data.elementOrText.embeddedViews.indexOf((<ViewRef_>viewRef)._view);
}
remove(index?: number): void {
@ -126,6 +128,6 @@ class TemplateRef_ implements TemplateRef<any> {
}
get elementRef(): ElementRef {
return new ElementRef(this._parentView.nodes[this._def.index].renderNode);
return new ElementRef(this._parentView.nodes[this._def.index].elementOrText.node);
}
}

View File

@ -44,7 +44,7 @@ export function textDef(constants: string[]): NodeDef {
}
export function createText(view: ViewData, renderHost: any, def: NodeDef): NodeData {
const parentNode = def.parent != null ? view.nodes[def.parent].renderNode : renderHost;
const parentNode = def.parent != null ? view.nodes[def.parent].elementOrText.node : renderHost;
let renderNode: any;
if (view.renderer) {
renderNode = view.renderer.createText(parentNode, def.text.prefix);
@ -54,7 +54,11 @@ export function createText(view: ViewData, renderHost: any, def: NodeDef): NodeD
parentNode.appendChild(renderNode);
}
}
return {renderNode, provider: undefined, embeddedViews: undefined, componentView: undefined};
return {
elementOrText: {node: renderNode, embeddedViews: undefined},
provider: undefined,
pureExpression: undefined
};
}
export function checkAndUpdateTextInline(
@ -112,7 +116,7 @@ export function checkAndUpdateTextInline(
value = _addInterpolationPart(v0, bindings[0]) + value;
}
value = def.text.prefix + value;
const renderNode = view.nodes[def.index].renderNode;
const renderNode = view.nodes[def.index].elementOrText.node;
if (view.renderer) {
view.renderer.setText(renderNode, value);
} else {
@ -137,7 +141,7 @@ export function checkAndUpdateTextDynamic(view: ViewData, def: NodeDef, values:
value = value + _addInterpolationPart(values[i], bindings[i]);
}
value = def.text.prefix + value;
const renderNode = view.nodes[def.index].renderNode;
const renderNode = view.nodes[def.index].elementOrText.node;
if (view.renderer) {
view.renderer.setText(renderNode, value);
} else {

View File

@ -206,12 +206,21 @@ export type DisposableFn = () => void;
* Attention: Adding fields to this is performance sensitive!
*/
export interface NodeData {
renderNode: any;
provider: PureExpressionData|any;
componentView: ViewData;
elementOrText: ElementOrTextData;
provider: ProviderData;
pureExpression: PureExpressionData;
}
export interface ElementOrTextData {
node: any;
embeddedViews: ViewData[];
}
export interface ProviderData {
instance: any;
componentView: ViewData;
}
export interface PureExpressionData {
value: any;
pipe: PipeTransform;

View File

@ -13,7 +13,7 @@ import {checkAndUpdateElementDynamic, checkAndUpdateElementInline, createElement
import {callLifecycleHooksChildrenFirst, checkAndUpdateProviderDynamic, checkAndUpdateProviderInline, createProvider} from './provider';
import {checkAndUpdatePureExpressionDynamic, checkAndUpdatePureExpressionInline, createPureExpression} from './pure_expression';
import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text';
import {ElementDef, NodeData, NodeDef, NodeFlags, NodeType, NodeUpdater, ProviderDef, PureExpressionData, Services, TextDef, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn} from './types';
import {ElementDef, NodeData, NodeDef, NodeFlags, NodeType, NodeUpdater, ProviderData, ProviderDef, Services, TextDef, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewUpdateFn} from './types';
import {checkBindingNoChanges} from './util';
const NOOP = (): any => undefined;
@ -274,8 +274,7 @@ const CheckNoChanges: NodeUpdater = {
checkBindingNoChanges(view, nodeDef, 0, v0);
}
if (nodeDef.type === NodeType.PureExpression) {
const data: PureExpressionData = view.nodes[index].provider;
return data.value;
return view.nodes[index].pureExpression.value;
}
return undefined;
},
@ -285,8 +284,7 @@ const CheckNoChanges: NodeUpdater = {
checkBindingNoChanges(view, nodeDef, i, values[i]);
}
if (nodeDef.type === NodeType.PureExpression) {
const data: PureExpressionData = view.nodes[index].provider;
return data.value;
return view.nodes[index].pureExpression.value;
}
return undefined;
}
@ -321,8 +319,7 @@ const CheckAndUpdate: NodeUpdater = {
return undefined;
case NodeType.PureExpression:
checkAndUpdatePureExpressionInline(view, nodeDef, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
const data: PureExpressionData = view.nodes[index].provider;
return data.value;
return view.nodes[index].pureExpression.value;
}
},
checkDynamic: (view: ViewData, index: number, values: any[]): void => {
@ -339,8 +336,7 @@ const CheckAndUpdate: NodeUpdater = {
return undefined;
case NodeType.PureExpression:
checkAndUpdatePureExpressionDynamic(view, nodeDef, values);
const data: PureExpressionData = view.nodes[index].provider;
return data.value;
return view.nodes[index].pureExpression.value;
}
}
};
@ -374,13 +370,15 @@ function execComponentViewsAction(view: ViewData, action: ViewAction) {
// a leaf
const nodeData = view.nodes[i];
if (action === ViewAction.InitComponent) {
let renderHost = view.nodes[nodeDef.parent].renderNode;
let renderHost = view.nodes[nodeDef.parent].elementOrText.node;
if (view.renderer) {
renderHost = view.renderer.createViewRoot(renderHost);
}
initView(nodeData.componentView, renderHost, nodeData.provider, nodeData.provider);
initView(
nodeData.provider.componentView, renderHost, nodeData.provider.instance,
nodeData.provider.instance);
} else {
callViewAction(nodeData.componentView, action);
callViewAction(nodeData.provider.componentView, action);
}
} else if ((nodeDef.childFlags & NodeFlags.HasComponent) === 0) {
// a parent with leafs
@ -401,7 +399,7 @@ function execEmbeddedViewsAction(view: ViewData, action: ViewAction) {
if (nodeDef.flags & NodeFlags.HasEmbeddedViews) {
// a leaf
const nodeData = view.nodes[i];
const embeddedViews = nodeData.embeddedViews;
const embeddedViews = nodeData.elementOrText.embeddedViews;
if (embeddedViews) {
for (let k = 0; k < embeddedViews.length; k++) {
callViewAction(embeddedViews[k], action);

View File

@ -9,7 +9,7 @@
import {NodeData, NodeFlags, ViewData} from './types';
export function attachEmbeddedView(node: NodeData, viewIndex: number, view: ViewData) {
let embeddedViews = node.embeddedViews;
let embeddedViews = node.elementOrText.embeddedViews;
if (viewIndex == null) {
viewIndex = embeddedViews.length;
}
@ -21,7 +21,7 @@ export function attachEmbeddedView(node: NodeData, viewIndex: number, view: View
}
const prevView = viewIndex > 0 ? embeddedViews[viewIndex - 1] : null;
const prevNode = prevView ? prevView.nodes[prevView.def.lastRootNode] : node;
const prevRenderNode = prevNode.renderNode;
const prevRenderNode = prevNode.elementOrText.node;
if (view.renderer) {
view.renderer.attachViewAfter(prevRenderNode, rootRenderNodes(view));
} else {
@ -35,7 +35,8 @@ export function attachEmbeddedView(node: NodeData, viewIndex: number, view: View
}
export function detachEmbeddedView(node: NodeData, viewIndex: number): ViewData {
const embeddedViews = node.embeddedViews;
const renderData = node.elementOrText;
const embeddedViews = renderData.embeddedViews;
if (viewIndex == null) {
viewIndex = embeddedViews.length;
}
@ -49,7 +50,7 @@ export function detachEmbeddedView(node: NodeData, viewIndex: number): ViewData
if (view.renderer) {
view.renderer.detachView(rootRenderNodes(view));
} else {
const parentNode = node.renderNode.parentNode;
const parentNode = renderData.node.parentNode;
if (parentNode) {
directDomAttachDetachSiblingRenderNodes(
view, 0, DirectDomAction.RemoveChild, parentNode, null);
@ -67,8 +68,8 @@ export function rootRenderNodes(view: ViewData): any[] {
function collectSiblingRenderNodes(view: ViewData, startIndex: number, target: any[]) {
for (let i = startIndex; i < view.nodes.length; i++) {
const nodeDef = view.def.nodes[i];
const nodeData = view.nodes[i];
target.push(nodeData.renderNode);
const nodeData = view.nodes[i].elementOrText;
target.push(nodeData.node);
if (nodeDef.flags & NodeFlags.HasEmbeddedViews) {
const embeddedViews = nodeData.embeddedViews;
if (embeddedViews) {
@ -93,16 +94,16 @@ function directDomAttachDetachSiblingRenderNodes(
nextSibling: any) {
for (let i = startIndex; i < view.nodes.length; i++) {
const nodeDef = view.def.nodes[i];
const nodeData = view.nodes[i];
const nodeData = view.nodes[i].elementOrText;
switch (action) {
case DirectDomAction.AppendChild:
parentNode.appendChild(nodeData.renderNode);
parentNode.appendChild(nodeData.node);
break;
case DirectDomAction.InsertBefore:
parentNode.insertBefore(nodeData.renderNode, nextSibling);
parentNode.insertBefore(nodeData.node, nextSibling);
break;
case DirectDomAction.RemoveChild:
parentNode.removeChild(nodeData.renderNode);
parentNode.removeChild(nodeData.node);
break;
}
if (nodeDef.flags & NodeFlags.HasEmbeddedViews) {

View File

@ -58,7 +58,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
])),
]));
const compView = view.nodes[1].componentView;
const compView = view.nodes[1].provider.componentView;
expect(compView.context).toBe(instance);
expect(compView.component).toBe(instance);
@ -85,7 +85,7 @@ function defineTests(config: {directDom: boolean, viewFlags: number}) {
], update
)),
], jasmine.createSpy('parentUpdater')));
const compView = view.nodes[1].componentView;
const compView = view.nodes[1].provider.componentView;
checkAndUpdateView(view);

View File

@ -53,7 +53,7 @@ export function main() {
updater, inlineDynamic, view, 2,
[callUpdater(updater, inlineDynamic, view, 1, values)]);
}));
const service = view.nodes[2].provider;
const service = view.nodes[2].provider.instance;
values = [1, 2];
checkAndUpdateView(view);
@ -87,7 +87,7 @@ export function main() {
updater, inlineDynamic, view, 2,
[callUpdater(updater, inlineDynamic, view, 1, values)]);
}));
const service = view.nodes[2].provider;
const service = view.nodes[2].provider.instance;
values = [1, 2];
checkAndUpdateView(view);
@ -126,7 +126,7 @@ export function main() {
updater, inlineDynamic, view, 3,
[callUpdater(updater, inlineDynamic, view, 2, values)]);
}));
const service = view.nodes[3].provider;
const service = view.nodes[3].provider.instance;
values = [1, 2];
checkAndUpdateView(view);

View File

@ -84,8 +84,8 @@ export class AppModule {
}
bootstrap() {
this.rootView = createRootView(new DefaultServices(null, this.sanitizer), TreeComponent_Host);
this.rootComp = this.rootView.nodes[1].provider;
this.rootEl = this.rootView.nodes[0].renderNode;
this.rootComp = this.rootView.nodes[1].provider.instance;
this.rootEl = this.rootView.nodes[0].elementOrText.node;
}
tick() { checkAndUpdateView(this.rootView); }
}