refactor(core): view engine - move handleEvent function from view to element

Some versions of TypeScript are super slow to compile functions that
contain a lot of `if` conditions in them. Splitting the handle event
expressions per element is similar to what we did in the old codegen.
This commit is contained in:
Tobias Bosch
2017-02-20 12:15:03 -08:00
committed by Igor Minar
parent 58ba4f0409
commit 32012a1ffb
16 changed files with 187 additions and 183 deletions

View File

@ -15,9 +15,9 @@ import {createRootView, isBrowser} from './helper';
export function main() {
describe(`View Anchor`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn): ViewDefinition {
return viewDef(ViewFlags.None, nodes, updateDirectives, updateRenderer, handleEvent);
nodes: NodeDef[], updateDirectives?: ViewUpdateFn,
updateRenderer?: ViewUpdateFn): ViewDefinition {
return viewDef(ViewFlags.None, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(

View File

@ -16,8 +16,8 @@ export function main() {
describe(`Component Views`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {
@ -191,7 +191,7 @@ export function main() {
[
elementDef(NodeFlags.None, null, null, 0, 'span', null, null, ['click']),
],
update, null, null, ViewFlags.OnPush)),
update, null, ViewFlags.OnPush)),
],
(check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); }));

View File

@ -17,8 +17,8 @@ export function main() {
describe(`View Elements`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(
@ -189,18 +189,16 @@ export function main() {
const handleEventSpy = jasmine.createSpy('handleEvent');
const removeListenerSpy =
spyOn(HTMLElement.prototype, 'removeEventListener').and.callThrough();
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
[elementDef(NodeFlags.None, null, null, 0, 'button', null, null, ['click'])], null,
null, handleEventSpy));
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
NodeFlags.None, null, null, 0, 'button', null, null, ['click'], handleEventSpy)]));
rootNodes[0].click();
expect(handleEventSpy).toHaveBeenCalled();
let handleEventArgs = handleEventSpy.calls.mostRecent().args;
expect(handleEventArgs[0]).toBe(view);
expect(handleEventArgs[1]).toBe(0);
expect(handleEventArgs[2]).toBe('click');
expect(handleEventArgs[3]).toBeTruthy();
expect(handleEventArgs[1]).toBe('click');
expect(handleEventArgs[2]).toBeTruthy();
Services.destroyView(view);
@ -211,11 +209,9 @@ export function main() {
const handleEventSpy = jasmine.createSpy('handleEvent');
const addListenerSpy = spyOn(window, 'addEventListener');
const removeListenerSpy = spyOn(window, 'removeEventListener');
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
[elementDef(
NodeFlags.None, null, null, 0, 'button', null, null,
[['window', 'windowClick']])],
null, null, handleEventSpy));
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
NodeFlags.None, null, null, 0, 'button', null, null, [['window', 'windowClick']],
handleEventSpy)]));
expect(addListenerSpy).toHaveBeenCalled();
expect(addListenerSpy.calls.mostRecent().args[0]).toBe('windowClick');
@ -224,9 +220,8 @@ export function main() {
expect(handleEventSpy).toHaveBeenCalled();
const handleEventArgs = handleEventSpy.calls.mostRecent().args;
expect(handleEventArgs[0]).toBe(view);
expect(handleEventArgs[1]).toBe(0);
expect(handleEventArgs[2]).toBe('window:windowClick');
expect(handleEventArgs[3]).toBeTruthy();
expect(handleEventArgs[1]).toBe('window:windowClick');
expect(handleEventArgs[2]).toBeTruthy();
Services.destroyView(view);
@ -237,11 +232,9 @@ export function main() {
const handleEventSpy = jasmine.createSpy('handleEvent');
const addListenerSpy = spyOn(document, 'addEventListener');
const removeListenerSpy = spyOn(document, 'removeEventListener');
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
[elementDef(
NodeFlags.None, null, null, 0, 'button', null, null,
[['document', 'documentClick']])],
null, null, handleEventSpy));
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
NodeFlags.None, null, null, 0, 'button', null, null, [['document', 'documentClick']],
handleEventSpy)]));
expect(addListenerSpy).toHaveBeenCalled();
expect(addListenerSpy.calls.mostRecent().args[0]).toBe('documentClick');
@ -250,9 +243,8 @@ export function main() {
expect(handleEventSpy).toHaveBeenCalled();
const handleEventArgs = handleEventSpy.calls.mostRecent().args;
expect(handleEventArgs[0]).toBe(view);
expect(handleEventArgs[1]).toBe(0);
expect(handleEventArgs[2]).toBe('document:documentClick');
expect(handleEventArgs[3]).toBeTruthy();
expect(handleEventArgs[1]).toBe('document:documentClick');
expect(handleEventArgs[2]).toBeTruthy();
Services.destroyView(view);
@ -263,12 +255,12 @@ export function main() {
let eventHandlerResult: any;
let preventDefaultSpy: jasmine.Spy;
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
[elementDef(NodeFlags.None, null, null, 0, 'button', null, null, ['click'])], null,
null, (view, index, eventName, event) => {
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef(
NodeFlags.None, null, null, 0, 'button', null, null, ['click'],
(view, eventName, event) => {
preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough();
return eventHandlerResult;
}));
})]));
eventHandlerResult = undefined;
rootNodes[0].click();
@ -290,8 +282,9 @@ export function main() {
it('should report debug info on event errors', () => {
const addListenerSpy = spyOn(HTMLElement.prototype, 'addEventListener').and.callThrough();
const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef(
[elementDef(NodeFlags.None, null, null, 0, 'button', null, null, ['click'])], null,
null, () => { throw new Error('Test'); }));
[elementDef(NodeFlags.None, null, null, 0, 'button', null, null, ['click'], () => {
throw new Error('Test');
})]));
let err: any;
try {

View File

@ -17,8 +17,8 @@ export function main() {
describe(`Embedded Views`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
@ -40,7 +40,7 @@ export function main() {
compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
anchorDef(
NodeFlags.HasEmbeddedViews, null, null, 0,
NodeFlags.HasEmbeddedViews, null, null, 0, null,
embeddedViewDef([elementDef(NodeFlags.None, null, null, 0, 'span')])),
]),
parentContext);
@ -54,10 +54,10 @@ export function main() {
it('should attach and detach embedded views', () => {
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 2, 'div'),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
])),
anchorDef(NodeFlags.None, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.None, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child1']])
]))
]));
@ -84,10 +84,10 @@ export function main() {
it('should move embedded views', () => {
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 2, 'div'),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
])),
anchorDef(NodeFlags.None, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.None, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child1']])
]))
]));
@ -111,7 +111,7 @@ export function main() {
it('should include embedded views in root nodes', () => {
const {view: parentView} = createAndGetRootNodes(compViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'child0']])
])),
elementDef(NodeFlags.None, null, null, 0, 'span', [['name', 'after']])
@ -136,7 +136,7 @@ export function main() {
const {view: parentView, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
anchorDef(
NodeFlags.HasEmbeddedViews, null, null, 0,
NodeFlags.HasEmbeddedViews, null, null, 0, null,
embeddedViewDef(
[elementDef(
NodeFlags.None, null, null, 0, 'span', null,
@ -172,7 +172,7 @@ export function main() {
const {view: parentView} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 1, 'span'),
directiveDef(NodeFlags.OnDestroy, null, 0, ChildProvider, [])
]))

View File

@ -16,8 +16,8 @@ export function main() {
describe(`View NgContent`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
@ -85,8 +85,8 @@ export function main() {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef(
[
anchorDef(
NodeFlags.HasEmbeddedViews, null, 0, 1, embeddedViewDef([textDef(null, ['a'])])),
anchorDef(NodeFlags.HasEmbeddedViews, null, 0, 1, null, embeddedViewDef([textDef(
null, ['a'])])),
directiveDef(
NodeFlags.None, null, 0, CreateViewService, [TemplateRef, ViewContainerRef])
],
@ -103,7 +103,7 @@ export function main() {
it('should include projected nodes when attaching / detaching embedded views', () => {
const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef([textDef(0, ['a'])], [
elementDef(NodeFlags.None, null, null, 1, 'div'),
anchorDef(NodeFlags.HasEmbeddedViews, null, 0, 0, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, 0, 0, null, embeddedViewDef([
ngContentDef(null, 0),
// The anchor would be added by the compiler after the ngContent
anchorDef(NodeFlags.None, null, null, 0),

View File

@ -18,8 +18,8 @@ export function main() {
describe(`View Providers`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
@ -238,8 +238,8 @@ export function main() {
it('should inject TemplateRef', () => {
createAndGetRootNodes(compViewDef([
anchorDef(NodeFlags.None, null, null, 1, embeddedViewDef([anchorDef(
NodeFlags.None, null, null, 0)])),
anchorDef(NodeFlags.None, null, null, 1, null, embeddedViewDef([anchorDef(
NodeFlags.None, null, null, 0)])),
directiveDef(NodeFlags.None, null, 0, SomeService, [TemplateRef])
]));
@ -365,16 +365,14 @@ export function main() {
const handleEvent = jasmine.createSpy('handleEvent');
const subscribe = spyOn(emitter, 'subscribe').and.callThrough();
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null, null, 1, 'span'),
directiveDef(
NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'})
],
null, null, handleEvent));
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'span', null, null, null, handleEvent),
directiveDef(
NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'})
]));
emitter.emit('someEventInstance');
expect(handleEvent).toHaveBeenCalledWith(view, 0, 'someEventName', 'someEventInstance');
expect(handleEvent).toHaveBeenCalledWith(view, 'someEventName', 'someEventInstance');
Services.destroyView(view);
expect(unsubscribeSpy).toHaveBeenCalled();
@ -387,13 +385,13 @@ export function main() {
emitter = emitter;
}
const {view, rootNodes} = createAndGetRootNodes(compViewDef(
[
elementDef(NodeFlags.None, null, null, 1, 'span'),
directiveDef(
NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'})
],
null, null, () => { throw new Error('Test'); }));
const {view, rootNodes} = createAndGetRootNodes(compViewDef([
elementDef(
NodeFlags.None, null, null, 1, 'span', null, null, null,
() => { throw new Error('Test'); }),
directiveDef(
NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'})
]));
let err: any;
try {

View File

@ -16,8 +16,8 @@ export function main() {
describe(`View Pure Expressions`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(viewDef: ViewDefinition): {rootNodes: any[], view: ViewData} {

View File

@ -18,8 +18,8 @@ export function main() {
describe(`Query Views`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function embeddedViewDef(nodes: NodeDef[], update?: ViewUpdateFn): ViewDefinitionFactory {
@ -145,7 +145,7 @@ export function main() {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 5, 'div'),
...contentQueryProviders(),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 2, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 2, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(),
])),
@ -171,7 +171,7 @@ export function main() {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 3, 'div'),
...contentQueryProviders(),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(),
])),
@ -200,7 +200,7 @@ export function main() {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 3, 'div'),
...contentQueryProviders(),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(),
])),
@ -227,7 +227,7 @@ export function main() {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
...viewQueryProviders([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(),
])),
@ -328,7 +328,7 @@ export function main() {
const {view} = createAndGetRootNodes(compViewDef([
anchorDef(
NodeFlags.None, [[someQueryId, QueryValueType.TemplateRef]], null, 2,
NodeFlags.None, [[someQueryId, QueryValueType.TemplateRef]], null, 2, null,
embeddedViewDef([anchorDef(NodeFlags.None, null, null, 0)])),
directiveDef(NodeFlags.None, null, 1, QueryService, []),
queryDef(
@ -367,7 +367,7 @@ export function main() {
const {view} = createAndGetRootNodes(compViewDef([
elementDef(NodeFlags.None, null, null, 3, 'div'),
...contentQueryProviders(),
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, embeddedViewDef([
anchorDef(NodeFlags.HasEmbeddedViews, null, null, 0, null, embeddedViewDef([
elementDef(NodeFlags.None, null, null, 1, 'div'),
aServiceProvider(),
])),

View File

@ -17,8 +17,8 @@ export function main() {
describe('View Services', () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(

View File

@ -17,8 +17,8 @@ export function main() {
describe(`View Text`, () => {
function compViewDef(
nodes: NodeDef[], updateDirectives?: ViewUpdateFn, updateRenderer?: ViewUpdateFn,
handleEvent?: ViewHandleEventFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer, handleEvent);
viewFlags: ViewFlags = ViewFlags.None): ViewDefinition {
return viewDef(viewFlags, nodes, updateDirectives, updateRenderer);
}
function createAndGetRootNodes(

View File

@ -232,7 +232,7 @@ export function main() {
const vd = viewDef(ViewFlags.None, [
elementDef(NodeFlags.None, null, null, 1, 'span'),
anchorDef(
NodeFlags.None, null, null, 0,
NodeFlags.None, null, null, 0, null,
() => viewDef(
ViewFlags.None,
[