refactor(core): replace loadLContext with getLContext calls (#41606)
This commit refactors the code to replace `loadLContext` with `getLContext` calls. The only difference between these two functions is that the `loadLContext` supports throwing an error in case `LContext` can not be found. The investigation performed in #41525 revealed that throwing while retrieving `LContext` might have undesirable performance implications, so we should avoid that to make sure there are no accidental perf regressions in other parts of code that used `loadLContext`. Moreover, in most of the places the `loadLContext` was already called in a mode that prevented an error from being thrown, so this refactoring should have no effect on the actual behavior. PR Close #41606
This commit is contained in:
parent
64567d3d39
commit
3ceb3dea67
|
@ -8,11 +8,12 @@
|
|||
|
||||
import {Injector} from '../di/injector';
|
||||
import {assertTNodeForLView} from '../render3/assert';
|
||||
import {getLContext} from '../render3/context_discovery';
|
||||
import {CONTAINER_HEADER_OFFSET, LContainer, NATIVE} from '../render3/interfaces/container';
|
||||
import {TElementNode, TNode, TNodeFlags, TNodeType} from '../render3/interfaces/node';
|
||||
import {isComponentHost, isLContainer} from '../render3/interfaces/type_checks';
|
||||
import {DECLARATION_COMPONENT_VIEW, LView, PARENT, T_HOST, TData, TVIEW} from '../render3/interfaces/view';
|
||||
import {getComponent, getContext, getInjectionTokens, getInjector, getListeners, getLocalRefs, getOwningComponent, loadLContext} from '../render3/util/discovery_utils';
|
||||
import {getComponent, getContext, getInjectionTokens, getInjector, getListeners, getLocalRefs, getOwningComponent} from '../render3/util/discovery_utils';
|
||||
import {INTERPOLATION_DELIMITER} from '../render3/util/misc_utils';
|
||||
import {renderStringify} from '../render3/util/stringify_utils';
|
||||
import {getComponentLViewByIndex, getNativeByTNodeOrNull} from '../render3/util/view_utils';
|
||||
|
@ -261,13 +262,13 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme
|
|||
}
|
||||
|
||||
get name(): string {
|
||||
try {
|
||||
const context = loadLContext(this.nativeNode)!;
|
||||
const context = getLContext(this.nativeNode);
|
||||
if (context !== null) {
|
||||
const lView = context.lView;
|
||||
const tData = lView[TVIEW].data;
|
||||
const tNode = tData[context.nodeIndex] as TNode;
|
||||
return tNode.value!;
|
||||
} catch (e) {
|
||||
} else {
|
||||
return this.nativeNode.nodeName;
|
||||
}
|
||||
}
|
||||
|
@ -285,8 +286,8 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme
|
|||
* - attribute bindings (e.g. `[attr.role]="menu"`)
|
||||
*/
|
||||
get properties(): {[key: string]: any;} {
|
||||
const context = loadLContext(this.nativeNode, false);
|
||||
if (context == null) {
|
||||
const context = getLContext(this.nativeNode);
|
||||
if (context === null) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -311,8 +312,8 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme
|
|||
return attributes;
|
||||
}
|
||||
|
||||
const context = loadLContext(element, false);
|
||||
if (context == null) {
|
||||
const context = getLContext(element);
|
||||
if (context === null) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -501,7 +502,7 @@ function _queryAllR3(
|
|||
function _queryAllR3(
|
||||
parentElement: DebugElement, predicate: Predicate<DebugElement>|Predicate<DebugNode>,
|
||||
matches: DebugElement[]|DebugNode[], elementsOnly: boolean) {
|
||||
const context = loadLContext(parentElement.nativeNode, false);
|
||||
const context = getLContext(parentElement.nativeNode);
|
||||
if (context !== null) {
|
||||
const parentTNode = context.lView[TVIEW].data[context.nodeIndex] as TNode;
|
||||
_queryNodeChildrenR3(
|
||||
|
|
|
@ -53,7 +53,7 @@ import {getTNode, unwrapRNode} from './view_utils';
|
|||
*/
|
||||
export function getComponent<T>(element: Element): T|null {
|
||||
assertDomElement(element);
|
||||
const context = loadLContext(element, false);
|
||||
const context = getLContext(element);
|
||||
if (context === null) return null;
|
||||
|
||||
if (context.component === undefined) {
|
||||
|
@ -78,7 +78,7 @@ export function getComponent<T>(element: Element): T|null {
|
|||
*/
|
||||
export function getContext<T>(element: Element): T|null {
|
||||
assertDomElement(element);
|
||||
const context = loadLContext(element, false);
|
||||
const context = getLContext(element);
|
||||
return context === null ? null : context.lView[CONTEXT] as T;
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ export function getContext<T>(element: Element): T|null {
|
|||
* @globalApi ng
|
||||
*/
|
||||
export function getOwningComponent<T>(elementOrDir: Element|{}): T|null {
|
||||
const context = loadLContext(elementOrDir, false);
|
||||
const context = getLContext(elementOrDir);
|
||||
if (context === null) return null;
|
||||
|
||||
let lView = context.lView;
|
||||
|
@ -136,7 +136,7 @@ export function getRootComponents(elementOrDir: Element|{}): {}[] {
|
|||
* @globalApi ng
|
||||
*/
|
||||
export function getInjector(elementOrDir: Element|{}): Injector {
|
||||
const context = loadLContext(elementOrDir, false);
|
||||
const context = getLContext(elementOrDir);
|
||||
if (context === null) return Injector.NULL;
|
||||
|
||||
const tNode = context.lView[TVIEW].data[context.nodeIndex] as TElementNode;
|
||||
|
@ -149,7 +149,7 @@ export function getInjector(elementOrDir: Element|{}): Injector {
|
|||
* @param element Element for which the injection tokens should be retrieved.
|
||||
*/
|
||||
export function getInjectionTokens(element: Element): any[] {
|
||||
const context = loadLContext(element, false);
|
||||
const context = getLContext(element);
|
||||
if (context === null) return [];
|
||||
const lView = context.lView;
|
||||
const tView = lView[TVIEW];
|
||||
|
@ -200,7 +200,7 @@ export function getDirectives(node: Node): {}[] {
|
|||
return [];
|
||||
}
|
||||
|
||||
const context = loadLContext(node, false);
|
||||
const context = getLContext(node);
|
||||
if (context === null) {
|
||||
return [];
|
||||
}
|
||||
|
@ -284,22 +284,6 @@ export function getDirectiveMetadata(directiveOrComponentInstance: any): Compone
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns LContext associated with a target passed as an argument.
|
||||
* Throws if a given target doesn't have associated LContext.
|
||||
*/
|
||||
export function loadLContext(target: {}): LContext;
|
||||
export function loadLContext(target: {}, throwOnNotFound: false): LContext|null;
|
||||
export function loadLContext(target: {}, throwOnNotFound: boolean = true): LContext|null {
|
||||
const context = getLContext(target);
|
||||
if (!context && throwOnNotFound) {
|
||||
throw new Error(
|
||||
ngDevMode ? `Unable to find context associated with ${stringifyForError(target)}` :
|
||||
'Invalid ng target');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve map of local references.
|
||||
*
|
||||
|
@ -309,7 +293,7 @@ export function loadLContext(target: {}, throwOnNotFound: boolean = true): LCont
|
|||
* the local references.
|
||||
*/
|
||||
export function getLocalRefs(target: {}): {[key: string]: any} {
|
||||
const context = loadLContext(target, false);
|
||||
const context = getLContext(target);
|
||||
if (context === null) return {};
|
||||
|
||||
if (context.localRefs === undefined) {
|
||||
|
@ -349,11 +333,6 @@ export function getRenderedText(component: any): string {
|
|||
return hostElement.textContent || '';
|
||||
}
|
||||
|
||||
export function loadLContextFromNode(node: Node): LContext {
|
||||
if (!(node instanceof Node)) throw new Error('Expecting instance of DOM Element');
|
||||
return loadLContext(node)!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener configuration returned from `getListeners`.
|
||||
* @publicApi
|
||||
|
@ -405,7 +384,7 @@ export interface Listener {
|
|||
*/
|
||||
export function getListeners(element: Element): Listener[] {
|
||||
assertDomElement(element);
|
||||
const lContext = loadLContext(element, false);
|
||||
const lContext = getLContext(element);
|
||||
if (lContext === null) return [];
|
||||
|
||||
const lView = lContext.lView;
|
||||
|
@ -458,9 +437,15 @@ function isDirectiveDefHack(obj: any): obj is DirectiveDef<any> {
|
|||
* @param element DOM element which is owned by an existing component's view.
|
||||
*/
|
||||
export function getDebugNode(element: Element): DebugNode|null {
|
||||
let debugNode: DebugNode|null = null;
|
||||
if (ngDevMode && !(element instanceof Node)) {
|
||||
throw new Error('Expecting instance of DOM Element');
|
||||
}
|
||||
|
||||
const lContext = getLContext(element);
|
||||
if (lContext === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const lContext = loadLContextFromNode(element);
|
||||
const lView = lContext.lView;
|
||||
const nodeIndex = lContext.nodeIndex;
|
||||
if (nodeIndex !== -1) {
|
||||
|
@ -471,10 +456,10 @@ export function getDebugNode(element: Element): DebugNode|null {
|
|||
isLView(valueInLView) ? (valueInLView[T_HOST] as TNode) : getTNode(lView[TVIEW], nodeIndex);
|
||||
ngDevMode &&
|
||||
assertEqual(tNode.index, nodeIndex, 'Expecting that TNode at index is same as index');
|
||||
debugNode = buildDebugNode(tNode, lView);
|
||||
return buildDebugNode(tNode, lView);
|
||||
}
|
||||
|
||||
return debugNode;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -486,7 +471,7 @@ export function getDebugNode(element: Element): DebugNode|null {
|
|||
* @param target DOM element or component instance for which to retrieve the LView.
|
||||
*/
|
||||
export function getComponentLView(target: any): LView {
|
||||
const lContext = loadLContext(target);
|
||||
const lContext = getLContext(target)!;
|
||||
const nodeIndx = lContext.nodeIndex;
|
||||
const lView = lContext.lView;
|
||||
const componentLView = lView[nodeIndx];
|
||||
|
|
|
@ -17,8 +17,9 @@ import {getElementStyles} from '@angular/core/testing/src/styling';
|
|||
import {expect} from '@angular/core/testing/src/testing_internal';
|
||||
import {onlyInIvy} from '@angular/private/testing';
|
||||
|
||||
import {getLContext} from '../../src/render3/context_discovery';
|
||||
import {getHostElement, markDirty} from '../../src/render3/index';
|
||||
import {ComponentDebugMetadata, getComponent, getComponentLView, getContext, getDebugNode, getDirectiveMetadata, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getOwningComponent, getRootComponents, loadLContext} from '../../src/render3/util/discovery_utils';
|
||||
import {ComponentDebugMetadata, getComponent, getComponentLView, getContext, getDebugNode, getDirectiveMetadata, getDirectives, getInjectionTokens, getInjector, getListeners, getLocalRefs, getOwningComponent, getRootComponents} from '../../src/render3/util/discovery_utils';
|
||||
|
||||
onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => {
|
||||
let fixture: ComponentFixture<MyApp>;
|
||||
|
@ -270,9 +271,9 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('loadLContext', () => {
|
||||
describe('getLContext', () => {
|
||||
it('should work on components', () => {
|
||||
const lContext = loadLContext(child[0]);
|
||||
const lContext = getLContext(child[0])!;
|
||||
expect(lContext).toBeDefined();
|
||||
expect(lContext.native as any).toBe(child[0]);
|
||||
});
|
||||
|
@ -280,7 +281,7 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => {
|
|||
it('should work on templates', () => {
|
||||
const templateComment = Array.from((fixture.nativeElement as HTMLElement).childNodes)
|
||||
.find((node: ChildNode) => node.nodeType === Node.COMMENT_NODE)!;
|
||||
const lContext = loadLContext(templateComment);
|
||||
const lContext = getLContext(templateComment)!;
|
||||
expect(lContext).toBeDefined();
|
||||
expect(lContext.native as any).toBe(templateComment);
|
||||
});
|
||||
|
@ -290,7 +291,7 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => {
|
|||
.find(
|
||||
(node: ChildNode) => node.nodeType === Node.COMMENT_NODE &&
|
||||
node.textContent === `ng-container`)!;
|
||||
const lContext = loadLContext(ngContainerComment);
|
||||
const lContext = getLContext(ngContainerComment)!;
|
||||
expect(lContext).toBeDefined();
|
||||
expect(lContext.native as any).toBe(ngContainerComment);
|
||||
});
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Component} from '@angular/core';
|
||||
import {LView} from '@angular/core/src/render3/interfaces/view';
|
||||
import {getComponentLView, loadLContext} from '@angular/core/src/render3/util/discovery_utils';
|
||||
import {getLContext} from '@angular/core/src/render3/context_discovery';
|
||||
import {getComponentLView} from '@angular/core/src/render3/util/discovery_utils';
|
||||
import {createNamedArrayType} from '@angular/core/src/util/named_array_type';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {onlyInIvy} from '@angular/private/testing';
|
||||
|
@ -32,7 +32,7 @@ onlyInIvy('Debug information exist in ivy only').describe('ngDevMode debug', ()
|
|||
|
||||
TestBed.configureTestingModule({declarations: [MyApp], imports: [CommonModule]});
|
||||
const fixture = TestBed.createComponent(MyApp);
|
||||
const rootLView = loadLContext(fixture.nativeElement).lView;
|
||||
const rootLView = getLContext(fixture.nativeElement)!.lView;
|
||||
expect(rootLView.constructor.name).toEqual('LRootView');
|
||||
|
||||
const componentLView = getComponentLView(fixture.componentInstance);
|
||||
|
@ -41,7 +41,7 @@ onlyInIvy('Debug information exist in ivy only').describe('ngDevMode debug', ()
|
|||
const element: HTMLElement = fixture.nativeElement;
|
||||
fixture.detectChanges();
|
||||
const li = element.querySelector('li')!;
|
||||
const embeddedLView = loadLContext(li).lView;
|
||||
const embeddedLView = getLContext(li)!.lView;
|
||||
expect(embeddedLView.constructor.name).toEqual('LEmbeddedView_MyApp_li_1');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue