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:
@ -733,17 +733,35 @@ function getBindingNameAndInstruction(binding: ParsedProperty):
|
||||
}
|
||||
|
||||
function createHostListeners(eventBindings: ParsedEvent[], name?: string): o.Statement[] {
|
||||
return eventBindings.map(binding => {
|
||||
const listeners: o.Expression[][] = [];
|
||||
const syntheticListeners: o.Expression[][] = [];
|
||||
const instructions: o.Statement[] = [];
|
||||
|
||||
eventBindings.forEach(binding => {
|
||||
let bindingName = binding.name && sanitizeIdentifier(binding.name);
|
||||
const bindingFnName = binding.type === ParsedEventType.Animation ?
|
||||
prepareSyntheticListenerFunctionName(bindingName, binding.targetOrPhase) :
|
||||
bindingName;
|
||||
const handlerName = name && bindingName ? `${name}_${bindingFnName}_HostBindingHandler` : null;
|
||||
const params = prepareEventListenerParameters(BoundEvent.fromParsedEvent(binding), handlerName);
|
||||
const instruction =
|
||||
binding.type == ParsedEventType.Animation ? R3.componentHostSyntheticListener : R3.listener;
|
||||
return o.importExpr(instruction).callFn(params).toStmt();
|
||||
|
||||
if (binding.type == ParsedEventType.Animation) {
|
||||
syntheticListeners.push(params);
|
||||
} else {
|
||||
listeners.push(params);
|
||||
}
|
||||
});
|
||||
|
||||
if (syntheticListeners.length > 0) {
|
||||
instructions.push(
|
||||
chainedInstruction(R3.componentHostSyntheticListener, syntheticListeners).toStmt());
|
||||
}
|
||||
|
||||
if (listeners.length > 0) {
|
||||
instructions.push(chainedInstruction(R3.listener, listeners).toStmt());
|
||||
}
|
||||
|
||||
return instructions;
|
||||
}
|
||||
|
||||
function metadataAsSummary(meta: R3HostMetadata): CompileDirectiveSummary {
|
||||
|
@ -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[])) {
|
||||
|
Reference in New Issue
Block a user