fix(core): view engine - fix perf regressions (#14345)

- Make sure `NodeDef`s don’t fall into dictionary mode.
- Use strategy pattern to add debug information / checks, instead of constantly checking for `isDevMode`.
- introduce a very light weight `RendererV2` interface to not have duplicate
  code paths for direct and non direct rendering

The strategy pattern is implemented via the new `Services` object.

Part of #14013

PR Close #14345
This commit is contained in:
Tobias Bosch
2017-02-03 15:20:50 -08:00
committed by Miško Hevery
parent f6b5965a63
commit 24af51a623
28 changed files with 1250 additions and 1202 deletions

View File

@ -7,7 +7,7 @@
*/
import {Injector, RootRenderer, Sanitizer} from '@angular/core';
import {RootData, checkNodeDynamic, checkNodeInline} from '@angular/core/src/view/index';
import {ArgumentType, NodeCheckFn, RootData, Services, ViewData, ViewDefinition, initServicesIfNeeded} from '@angular/core/src/view/index';
import {TestBed} from '@angular/core/testing';
import {getDOM} from '@angular/platform-browser/src/dom/dom_adapter';
@ -15,53 +15,25 @@ export function isBrowser() {
return getDOM().supportsDOMEvents();
}
export function setupAndCheckRenderer(config: {directDom: boolean}) {
let rootRenderer: any;
if (config.directDom) {
beforeEach(() => {
rootRenderer = <any>{
renderComponent: jasmine.createSpy('renderComponent')
.and.throwError('Renderer should not have been called!')
};
TestBed.configureTestingModule(
{providers: [{provide: RootRenderer, useValue: rootRenderer}]});
});
afterEach(() => { expect(rootRenderer.renderComponent).not.toHaveBeenCalled(); });
} else {
beforeEach(() => {
rootRenderer = TestBed.get(RootRenderer);
spyOn(rootRenderer, 'renderComponent').and.callThrough();
});
afterEach(() => { expect(rootRenderer.renderComponent).toHaveBeenCalled(); });
export const ARG_TYPE_VALUES = [ArgumentType.Inline, ArgumentType.Dynamic];
export function checkNodeInlineOrDynamic(
check: NodeCheckFn, view: ViewData, nodeIndex: number, argType: ArgumentType,
values: any[]): any {
switch (argType) {
case ArgumentType.Inline:
return (<any>check)(view, nodeIndex, argType, ...values);
case ArgumentType.Dynamic:
return check(view, nodeIndex, argType, values);
}
}
export enum InlineDynamic {
Inline,
Dynamic
}
export const INLINE_DYNAMIC_VALUES = [InlineDynamic.Inline, InlineDynamic.Dynamic];
export function checkNodeInlineOrDynamic(inlineDynamic: InlineDynamic, values: any[]): any {
switch (inlineDynamic) {
case InlineDynamic.Inline:
return (<any>checkNodeInline)(...values);
case InlineDynamic.Dynamic:
return checkNodeDynamic(values);
}
}
export function createRootData(projectableNodes?: any[][], rootSelectorOrNode?: any): RootData {
const injector = TestBed.get(Injector);
const renderer = injector.get(RootRenderer);
const sanitizer = injector.get(Sanitizer);
projectableNodes = projectableNodes || [];
return <RootData>{
injector,
projectableNodes,
selectorOrNode: rootSelectorOrNode, sanitizer, renderer
};
export function createRootView(
def: ViewDefinition, context?: any, projectableNodes?: any[][],
rootSelectorOrNode?: any): ViewData {
initServicesIfNeeded();
return Services.createRootView(
TestBed.get(Injector), projectableNodes || [], rootSelectorOrNode, def, context);
}
export let removeNodes: Node[];