perf(ivy): chain listener instructions (#33720)

Chains multiple listener instructions on a particular element into a single call which results in less generated code. Also handles listeners on templates, host listeners and synthetic host listeners.

PR Close #33720
This commit is contained in:
crisbeto
2019-11-12 02:15:24 +09:00
committed by Kara Erickson
parent ccee818034
commit e31f62045d
10 changed files with 293 additions and 52 deletions

View File

@ -684,11 +684,14 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
}
// Generate Listeners (outputs)
element.outputs.forEach((outputAst: t.BoundEvent) => {
this.creationInstruction(
outputAst.sourceSpan, R3.listener,
this.prepareListenerParameter(element.name, outputAst, elementIndex));
});
if (element.outputs.length > 0) {
const listeners = element.outputs.map(
(outputAst: t.BoundEvent) => ({
sourceSpan: outputAst.sourceSpan,
params: this.prepareListenerParameter(element.name, outputAst, elementIndex)
}));
this.creationInstructionChain(R3.listener, listeners);
}
// Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
// listeners, to make sure i18nAttributes instruction targets current element at runtime.
@ -912,11 +915,14 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
// Add the input bindings
this.templatePropertyBindings(templateIndex, template.inputs);
// Generate listeners for directive output
template.outputs.forEach((outputAst: t.BoundEvent) => {
this.creationInstruction(
outputAst.sourceSpan, R3.listener,
this.prepareListenerParameter('ng_template', outputAst, templateIndex));
});
if (template.outputs.length > 0) {
const listeners = template.outputs.map(
(outputAst: t.BoundEvent) => ({
sourceSpan: outputAst.sourceSpan,
params: this.prepareListenerParameter('ng_template', outputAst, templateIndex)
}));
this.creationInstructionChain(R3.listener, listeners);
}
}
}
@ -1092,6 +1098,16 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
this.instructionFn(this._creationCodeFns, span, reference, paramsOrFn || [], prepend);
}
private creationInstructionChain(reference: o.ExternalReference, calls: {
sourceSpan: ParseSourceSpan | null,
params: () => o.Expression[]
}[]) {
const span = calls.length ? calls[0].sourceSpan : null;
this._creationCodeFns.push(() => {
return chainedInstruction(reference, calls.map(call => call.params()), span).toStmt();
});
}
private updateInstructionWithAdvance(
nodeIndex: number, span: ParseSourceSpan|null, reference: o.ExternalReference,
paramsOrFn?: o.Expression[]|(() => o.Expression[])) {