refactor(core): viewDef related refactoring (#19272)
- optimize the way node flags are propagated in `viewDef()`, - fix `elementDef()` signature to make `namespaceAndName` nullable, - move render parent computation with the parent computation PR Close #19272
This commit is contained in:
parent
f2bad195bc
commit
abceaa2f33
|
@ -55,7 +55,7 @@ export function anchorDef(
|
||||||
|
|
||||||
export function elementDef(
|
export function elementDef(
|
||||||
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
|
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
|
||||||
ngContentIndex: number, childCount: number, namespaceAndName: string,
|
ngContentIndex: number, childCount: number, namespaceAndName: string | null,
|
||||||
fixedAttrs: [string, string][] = [],
|
fixedAttrs: [string, string][] = [],
|
||||||
bindings?: [BindingFlags, string, string | SecurityContext][], outputs?: ([string, string])[],
|
bindings?: [BindingFlags, string, string | SecurityContext][], outputs?: ([string, string])[],
|
||||||
handleEvent?: ElementHandleEventFn, componentView?: ViewDefinitionFactory,
|
handleEvent?: ElementHandleEventFn, componentView?: ViewDefinitionFactory,
|
||||||
|
|
|
@ -233,6 +233,7 @@ export const enum QueryValueType {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ElementDef {
|
export interface ElementDef {
|
||||||
|
// set to null for `<ng-container>`
|
||||||
name: string|null;
|
name: string|null;
|
||||||
ns: string|null;
|
ns: string|null;
|
||||||
/** ns, name, value */
|
/** ns, name, value */
|
||||||
|
|
|
@ -30,34 +30,21 @@ export function viewDef(
|
||||||
let viewRootNodeFlags = 0;
|
let viewRootNodeFlags = 0;
|
||||||
let viewMatchedQueries = 0;
|
let viewMatchedQueries = 0;
|
||||||
let currentParent: NodeDef|null = null;
|
let currentParent: NodeDef|null = null;
|
||||||
|
let currentRenderParent: NodeDef|null = null;
|
||||||
let currentElementHasPublicProviders = false;
|
let currentElementHasPublicProviders = false;
|
||||||
let currentElementHasPrivateProviders = false;
|
let currentElementHasPrivateProviders = false;
|
||||||
let lastRenderRootNode: NodeDef|null = null;
|
let lastRenderRootNode: NodeDef|null = null;
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
while (currentParent && i > currentParent.index + currentParent.childCount) {
|
|
||||||
const newParent: NodeDef|null = currentParent.parent;
|
|
||||||
if (newParent) {
|
|
||||||
newParent.childFlags |= currentParent.childFlags !;
|
|
||||||
newParent.childMatchedQueries |= currentParent.childMatchedQueries;
|
|
||||||
}
|
|
||||||
currentParent = newParent;
|
|
||||||
}
|
|
||||||
const node = nodes[i];
|
const node = nodes[i];
|
||||||
node.index = i;
|
node.index = i;
|
||||||
node.parent = currentParent;
|
node.parent = currentParent;
|
||||||
node.bindingIndex = viewBindingCount;
|
node.bindingIndex = viewBindingCount;
|
||||||
node.outputIndex = viewDisposableCount;
|
node.outputIndex = viewDisposableCount;
|
||||||
|
|
||||||
// renderParent needs to account for ng-container!
|
|
||||||
let currentRenderParent: NodeDef|null;
|
|
||||||
if (currentParent && currentParent.flags & NodeFlags.TypeElement &&
|
|
||||||
!currentParent.element !.name) {
|
|
||||||
currentRenderParent = currentParent.renderParent;
|
|
||||||
} else {
|
|
||||||
currentRenderParent = currentParent;
|
|
||||||
}
|
|
||||||
node.renderParent = currentRenderParent;
|
node.renderParent = currentRenderParent;
|
||||||
|
|
||||||
|
viewNodeFlags |= node.flags;
|
||||||
|
viewMatchedQueries |= node.matchedQueryIds;
|
||||||
|
|
||||||
if (node.element) {
|
if (node.element) {
|
||||||
const elDef = node.element;
|
const elDef = node.element;
|
||||||
elDef.publicProviders =
|
elDef.publicProviders =
|
||||||
|
@ -66,24 +53,13 @@ export function viewDef(
|
||||||
// Note: We assume that all providers of an element are before any child element!
|
// Note: We assume that all providers of an element are before any child element!
|
||||||
currentElementHasPublicProviders = false;
|
currentElementHasPublicProviders = false;
|
||||||
currentElementHasPrivateProviders = false;
|
currentElementHasPrivateProviders = false;
|
||||||
|
|
||||||
|
if (node.element.template) {
|
||||||
|
viewMatchedQueries |= node.element.template.nodeMatchedQueries;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
validateNode(currentParent, node, nodes.length);
|
validateNode(currentParent, node, nodes.length);
|
||||||
|
|
||||||
viewNodeFlags |= node.flags;
|
|
||||||
viewMatchedQueries |= node.matchedQueryIds;
|
|
||||||
if (node.element && node.element.template) {
|
|
||||||
viewMatchedQueries |= node.element.template.nodeMatchedQueries;
|
|
||||||
}
|
|
||||||
if (currentParent) {
|
|
||||||
currentParent.childFlags |= node.flags;
|
|
||||||
currentParent.directChildFlags |= node.flags;
|
|
||||||
currentParent.childMatchedQueries |= node.matchedQueryIds;
|
|
||||||
if (node.element && node.element.template) {
|
|
||||||
currentParent.childMatchedQueries |= node.element.template.nodeMatchedQueries;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
viewRootNodeFlags |= node.flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
viewBindingCount += node.bindings.length;
|
viewBindingCount += node.bindings.length;
|
||||||
viewDisposableCount += node.outputs.length;
|
viewDisposableCount += node.outputs.length;
|
||||||
|
@ -91,6 +67,7 @@ export function viewDef(
|
||||||
if (!currentRenderParent && (node.flags & NodeFlags.CatRenderNode)) {
|
if (!currentRenderParent && (node.flags & NodeFlags.CatRenderNode)) {
|
||||||
lastRenderRootNode = node;
|
lastRenderRootNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.flags & NodeFlags.CatProvider) {
|
if (node.flags & NodeFlags.CatProvider) {
|
||||||
if (!currentElementHasPublicProviders) {
|
if (!currentElementHasPublicProviders) {
|
||||||
currentElementHasPublicProviders = true;
|
currentElementHasPublicProviders = true;
|
||||||
|
@ -106,7 +83,7 @@ export function viewDef(
|
||||||
} else {
|
} else {
|
||||||
if (!currentElementHasPrivateProviders) {
|
if (!currentElementHasPrivateProviders) {
|
||||||
currentElementHasPrivateProviders = true;
|
currentElementHasPrivateProviders = true;
|
||||||
// Use protoyypical inheritance to not get O(n^2) complexity...
|
// Use prototypical inheritance to not get O(n^2) complexity...
|
||||||
currentParent !.element !.allProviders =
|
currentParent !.element !.allProviders =
|
||||||
Object.create(currentParent !.element !.publicProviders);
|
Object.create(currentParent !.element !.publicProviders);
|
||||||
}
|
}
|
||||||
|
@ -116,20 +93,50 @@ export function viewDef(
|
||||||
currentParent !.element !.componentProvider = node;
|
currentParent !.element !.componentProvider = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node.childCount) {
|
|
||||||
|
if (currentParent) {
|
||||||
|
currentParent.childFlags |= node.flags;
|
||||||
|
currentParent.directChildFlags |= node.flags;
|
||||||
|
currentParent.childMatchedQueries |= node.matchedQueryIds;
|
||||||
|
if (node.element && node.element.template) {
|
||||||
|
currentParent.childMatchedQueries |= node.element.template.nodeMatchedQueries;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
viewRootNodeFlags |= node.flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.childCount > 0) {
|
||||||
currentParent = node;
|
currentParent = node;
|
||||||
|
|
||||||
|
if (!isNgContainer(node)) {
|
||||||
|
currentRenderParent = node;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
while (currentParent) {
|
// When the current node has no children, check if it is the last children of its parent.
|
||||||
const newParent = currentParent.parent;
|
// When it is, propagate the flags up.
|
||||||
|
// The loop is required because an element could be the last transitive children of several
|
||||||
|
// elements. We loop to either the root or the highest opened element (= with remaining
|
||||||
|
// children)
|
||||||
|
while (currentParent && i === currentParent.index + currentParent.childCount) {
|
||||||
|
const newParent: NodeDef|null = currentParent.parent;
|
||||||
if (newParent) {
|
if (newParent) {
|
||||||
newParent.childFlags |= currentParent.childFlags;
|
newParent.childFlags |= currentParent.childFlags;
|
||||||
newParent.childMatchedQueries |= currentParent.childMatchedQueries;
|
newParent.childMatchedQueries |= currentParent.childMatchedQueries;
|
||||||
}
|
}
|
||||||
currentParent = newParent;
|
currentParent = newParent;
|
||||||
|
// We also need to update the render parent & account for ng-container
|
||||||
|
if (currentParent && isNgContainer(currentParent)) {
|
||||||
|
currentRenderParent = currentParent.renderParent;
|
||||||
|
} else {
|
||||||
|
currentRenderParent = currentParent;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleEvent: ViewHandleEventFn = (view, nodeIndex, eventName, event) =>
|
const handleEvent: ViewHandleEventFn = (view, nodeIndex, eventName, event) =>
|
||||||
nodes[nodeIndex].element !.handleEvent !(view, eventName, event);
|
nodes[nodeIndex].element !.handleEvent !(view, eventName, event);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Will be filled later...
|
// Will be filled later...
|
||||||
factory: null,
|
factory: null,
|
||||||
|
@ -138,13 +145,16 @@ export function viewDef(
|
||||||
nodeMatchedQueries: viewMatchedQueries, flags,
|
nodeMatchedQueries: viewMatchedQueries, flags,
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
updateDirectives: updateDirectives || NOOP,
|
updateDirectives: updateDirectives || NOOP,
|
||||||
updateRenderer: updateRenderer || NOOP,
|
updateRenderer: updateRenderer || NOOP, handleEvent,
|
||||||
handleEvent: handleEvent || NOOP,
|
|
||||||
bindingCount: viewBindingCount,
|
bindingCount: viewBindingCount,
|
||||||
outputCount: viewDisposableCount, lastRenderRootNode
|
outputCount: viewDisposableCount, lastRenderRootNode
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isNgContainer(node: NodeDef): boolean {
|
||||||
|
return (node.flags & NodeFlags.TypeElement) !== 0 && node.element !.name === null;
|
||||||
|
}
|
||||||
|
|
||||||
function validateNode(parent: NodeDef | null, node: NodeDef, nodeCount: number) {
|
function validateNode(parent: NodeDef | null, node: NodeDef, nodeCount: number) {
|
||||||
const template = node.element && node.element.template;
|
const template = node.element && node.element.template;
|
||||||
if (template) {
|
if (template) {
|
||||||
|
|
Loading…
Reference in New Issue