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(
|
||||
flags: NodeFlags, matchedQueriesDsl: [string | number, QueryValueType][],
|
||||
ngContentIndex: number, childCount: number, namespaceAndName: string,
|
||||
ngContentIndex: number, childCount: number, namespaceAndName: string | null,
|
||||
fixedAttrs: [string, string][] = [],
|
||||
bindings?: [BindingFlags, string, string | SecurityContext][], outputs?: ([string, string])[],
|
||||
handleEvent?: ElementHandleEventFn, componentView?: ViewDefinitionFactory,
|
||||
|
|
|
@ -233,6 +233,7 @@ export const enum QueryValueType {
|
|||
}
|
||||
|
||||
export interface ElementDef {
|
||||
// set to null for `<ng-container>`
|
||||
name: string|null;
|
||||
ns: string|null;
|
||||
/** ns, name, value */
|
||||
|
|
|
@ -30,34 +30,21 @@ export function viewDef(
|
|||
let viewRootNodeFlags = 0;
|
||||
let viewMatchedQueries = 0;
|
||||
let currentParent: NodeDef|null = null;
|
||||
let currentRenderParent: NodeDef|null = null;
|
||||
let currentElementHasPublicProviders = false;
|
||||
let currentElementHasPrivateProviders = false;
|
||||
let lastRenderRootNode: NodeDef|null = null;
|
||||
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];
|
||||
node.index = i;
|
||||
node.parent = currentParent;
|
||||
node.bindingIndex = viewBindingCount;
|
||||
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;
|
||||
|
||||
viewNodeFlags |= node.flags;
|
||||
viewMatchedQueries |= node.matchedQueryIds;
|
||||
|
||||
if (node.element) {
|
||||
const elDef = node.element;
|
||||
elDef.publicProviders =
|
||||
|
@ -66,24 +53,13 @@ export function viewDef(
|
|||
// Note: We assume that all providers of an element are before any child element!
|
||||
currentElementHasPublicProviders = false;
|
||||
currentElementHasPrivateProviders = false;
|
||||
|
||||
if (node.element.template) {
|
||||
viewMatchedQueries |= node.element.template.nodeMatchedQueries;
|
||||
}
|
||||
}
|
||||
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;
|
||||
viewDisposableCount += node.outputs.length;
|
||||
|
@ -91,6 +67,7 @@ export function viewDef(
|
|||
if (!currentRenderParent && (node.flags & NodeFlags.CatRenderNode)) {
|
||||
lastRenderRootNode = node;
|
||||
}
|
||||
|
||||
if (node.flags & NodeFlags.CatProvider) {
|
||||
if (!currentElementHasPublicProviders) {
|
||||
currentElementHasPublicProviders = true;
|
||||
|
@ -106,7 +83,7 @@ export function viewDef(
|
|||
} else {
|
||||
if (!currentElementHasPrivateProviders) {
|
||||
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 =
|
||||
Object.create(currentParent !.element !.publicProviders);
|
||||
}
|
||||
|
@ -116,20 +93,50 @@ export function viewDef(
|
|||
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;
|
||||
|
||||
if (!isNgContainer(node)) {
|
||||
currentRenderParent = node;
|
||||
}
|
||||
} else {
|
||||
// When the current node has no children, check if it is the last children of its 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) {
|
||||
newParent.childFlags |= currentParent.childFlags;
|
||||
newParent.childMatchedQueries |= currentParent.childMatchedQueries;
|
||||
}
|
||||
currentParent = newParent;
|
||||
// We also need to update the render parent & account for ng-container
|
||||
if (currentParent && isNgContainer(currentParent)) {
|
||||
currentRenderParent = currentParent.renderParent;
|
||||
} else {
|
||||
currentRenderParent = currentParent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (currentParent) {
|
||||
const newParent = currentParent.parent;
|
||||
if (newParent) {
|
||||
newParent.childFlags |= currentParent.childFlags;
|
||||
newParent.childMatchedQueries |= currentParent.childMatchedQueries;
|
||||
}
|
||||
currentParent = newParent;
|
||||
}
|
||||
|
||||
const handleEvent: ViewHandleEventFn = (view, nodeIndex, eventName, event) =>
|
||||
nodes[nodeIndex].element !.handleEvent !(view, eventName, event);
|
||||
|
||||
return {
|
||||
// Will be filled later...
|
||||
factory: null,
|
||||
|
@ -138,13 +145,16 @@ export function viewDef(
|
|||
nodeMatchedQueries: viewMatchedQueries, flags,
|
||||
nodes: nodes,
|
||||
updateDirectives: updateDirectives || NOOP,
|
||||
updateRenderer: updateRenderer || NOOP,
|
||||
handleEvent: handleEvent || NOOP,
|
||||
updateRenderer: updateRenderer || NOOP, handleEvent,
|
||||
bindingCount: viewBindingCount,
|
||||
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) {
|
||||
const template = node.element && node.element.template;
|
||||
if (template) {
|
||||
|
|
Loading…
Reference in New Issue