perf(core): optimize getDirectives (#41525)
This commit introduces the following optimizations: 1. We return an empty array for text nodes in `getDirectives` because Angular does not support attaching logic to them. This optimization improves performance of `getDirectives` significantly because text nodes often result in expensive calls to `loadLContext` since we can't resolve it from a parent node. 1. `getDirectives` now calls `loadLContext` with second argument `false` so it doesn't throw an error. This brings another significant improvement because prevents the VM from deoptimizing calls. BREAKING CHANGE: Previously the `ng.getDirectives` function threw an error in case a given DOM node had no Angular context associated with it (for example if a function was called for a DOM element outside of an Angular app). This behavior was inconsistent with other debugging utilities under `ng` namespace, which handled this situation without raising an exception. Now calling the `ng.getDirectives` function for such DOM nodes would result in an empty array returned from that function. PR Close #41525
This commit is contained in:
parent
a07f303708
commit
f7e391a912
|
@ -172,7 +172,7 @@ export function getInjectionTokens(element: Element): any[] {
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieves directive instances associated with a given DOM element. Does not include
|
||||
* Retrieves directive instances associated with a given DOM node. Does not include
|
||||
* component instances.
|
||||
*
|
||||
* @usageNotes
|
||||
|
@ -184,21 +184,35 @@ export function getInjectionTokens(element: Element): any[] {
|
|||
* </my-app>
|
||||
* ```
|
||||
* Calling `getDirectives` on `<button>` will return an array with an instance of the `MyButton`
|
||||
* directive that is associated with the DOM element.
|
||||
* directive that is associated with the DOM node.
|
||||
*
|
||||
* Calling `getDirectives` on `<my-comp>` will return an empty array.
|
||||
*
|
||||
* @param element DOM element for which to get the directives.
|
||||
* @returns Array of directives associated with the element.
|
||||
* @param node DOM node for which to get the directives.
|
||||
* @returns Array of directives associated with the node.
|
||||
*
|
||||
* @publicApi
|
||||
* @globalApi ng
|
||||
*/
|
||||
export function getDirectives(element: Element): {}[] {
|
||||
const context = loadLContext(element)!;
|
||||
export function getDirectives(node: Node): {}[] {
|
||||
// Skip text nodes because we can't have directives associated with them.
|
||||
if (node instanceof Text) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const context = loadLContext(node, false);
|
||||
if (context === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const lView = context.lView;
|
||||
const tView = lView[TVIEW];
|
||||
const nodeIndex = context.nodeIndex;
|
||||
if (!tView?.data[nodeIndex]) {
|
||||
return [];
|
||||
}
|
||||
if (context.directives === undefined) {
|
||||
context.directives = getDirectivesAtNodeIndex(context.nodeIndex, context.lView, false);
|
||||
context.directives = getDirectivesAtNodeIndex(nodeIndex, lView, false);
|
||||
}
|
||||
|
||||
// The `directives` in this case are a named array called `LComponentView`. Clone the
|
||||
|
|
|
@ -386,9 +386,11 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () =>
|
|||
|
||||
it('should not throw if it cannot find LContext', () => {
|
||||
let result: any;
|
||||
|
||||
expect(() => {
|
||||
result = getDirectives(document.createElement('div'));
|
||||
}).not.toThrow();
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue