refactor(compiler): generate less code for bindings to DOM elements

Detailed changes:
- remove `UNINITIALIZED`, initialize change detection fields with `undefined`.
  * we use `view.numberOfChecks === 0` now everywhere
    as indicator whether we are in the first change detection cycle
    (previously we used this only in a couple of places).
  * we keep the initialization itself as change detection get slower without it.
- remove passing around `throwOnChange` in various generated calls,
  and store it on the view as property instead.
- change generated code for bindings to DOM elements as follows:
  Before:
  ```
  var currVal_10 = self.context.bgColor;
  if (jit_checkBinding15(self.throwOnChange,self._expr_10,currVal_10)) {
    self.renderer.setElementStyle(self._el_0,'backgroundColor',((self.viewUtils.sanitizer.sanitize(jit_21,currVal_10) == null)? null: self.viewUtils.sanitizer.sanitize(jit_21,currVal_10).toString()));
    self._expr_10 = currVal_10;
  }
  var currVal_11 = jit_inlineInterpolate16(1,' ',self.context.data.value,' ');
  if (jit_checkBinding15(self.throwOnChange,self._expr_11,currVal_11)) {
    self.renderer.setText(self._text_1,currVal_11);
    self._expr_11 = currVal_11;
  }
  ```,
  After:
  ```
  var currVal_10 = self.context.bgColor;
  jit_checkRenderStyle14(self,self._el_0,'backgroundColor',null,self._expr_10,self._expr_10=currVal_10,false,jit_21);
  var currVal_11 = jit_inlineInterpolate15(1,' ',self.context.data.value,' ');
  jit_checkRenderText16(self,self._text_1,self._expr_11,self._expr_11=currVal_11,false);
  ```

Performance impact:
- None seen (checked against internal latency lab)

Part of #13651
This commit is contained in:
Tobias Bosch
2016-12-29 15:03:55 -08:00
committed by Igor Minar
parent 8ed92d75b0
commit db49d422f2
23 changed files with 346 additions and 286 deletions

View File

@ -21,28 +21,14 @@ export function createCheckBindingField(builder: ClassBuilder): CheckBindingFiel
const fieldExpr = createBindFieldExpr(bindingId);
// private is fine here as no child view will reference the cached value...
builder.fields.push(new o.ClassField(fieldExpr.name, null, [o.StmtModifier.Private]));
builder.ctorStmts.push(o.THIS_EXPR.prop(fieldExpr.name)
.set(o.importExpr(createIdentifier(Identifiers.UNINITIALIZED)))
.toStmt());
builder.ctorStmts.push(o.THIS_EXPR.prop(fieldExpr.name).set(o.literal(undefined)).toStmt());
return new CheckBindingField(fieldExpr, bindingId);
}
export function createCheckBindingStmt(
evalResult: ConvertPropertyBindingResult, fieldExpr: o.ReadPropExpr,
throwOnChangeVar: o.Expression, actions: o.Statement[]): o.Statement[] {
let condition: o.Expression = o.importExpr(createIdentifier(Identifiers.checkBinding)).callFn([
throwOnChangeVar, fieldExpr, evalResult.currValExpr
]);
if (evalResult.forceUpdate) {
condition = evalResult.forceUpdate.or(condition);
}
return [
...evalResult.stmts, new o.IfStmt(condition, actions.concat([
<o.Statement>o.THIS_EXPR.prop(fieldExpr.name).set(evalResult.currValExpr).toStmt()
]))
];
}
function createBindFieldExpr(bindingId: string): o.ReadPropExpr {
return o.THIS_EXPR.prop(`_expr_${bindingId}`);
}
export function isFirstViewCheck(view: o.Expression): o.Expression {
return o.not(view.prop('numberOfChecks'));
}

View File

@ -13,69 +13,64 @@ import * as o from '../output/output_ast';
import {EMPTY_STATE as EMPTY_ANIMATION_STATE} from '../private_import_core';
import {BoundElementPropertyAst, BoundEventAst, PropertyBindingType} from '../template_parser/template_ast';
import {isFirstViewCheck} from './binding_util';
import {ConvertPropertyBindingResult} from './expression_converter';
import {createEnumExpression} from './identifier_util';
export function writeToRenderer(
view: o.Expression, boundProp: BoundElementPropertyAst, renderElement: o.Expression,
renderValue: o.Expression, logBindingUpdate: boolean,
export function createCheckRenderBindingStmt(
view: o.Expression, renderElement: o.Expression, boundProp: BoundElementPropertyAst,
oldValue: o.ReadPropExpr, evalResult: ConvertPropertyBindingResult,
securityContextExpression?: o.Expression): o.Statement[] {
const updateStmts: o.Statement[] = [];
const renderer = view.prop('renderer');
renderValue = sanitizedValue(view, boundProp, renderValue, securityContextExpression);
const checkStmts: o.Statement[] = [...evalResult.stmts];
const securityContext = calcSecurityContext(boundProp, securityContextExpression);
switch (boundProp.type) {
case PropertyBindingType.Property:
if (logBindingUpdate) {
updateStmts.push(
o.importExpr(createIdentifier(Identifiers.setBindingDebugInfo))
.callFn([renderer, renderElement, o.literal(boundProp.name), renderValue])
.toStmt());
}
updateStmts.push(
renderer
.callMethod(
'setElementProperty', [renderElement, o.literal(boundProp.name), renderValue])
.toStmt());
checkStmts.push(o.importExpr(createIdentifier(Identifiers.checkRenderProperty))
.callFn([
view, renderElement, o.literal(boundProp.name), oldValue,
oldValue.set(evalResult.currValExpr),
evalResult.forceUpdate || o.literal(false), securityContext
])
.toStmt());
break;
case PropertyBindingType.Attribute:
renderValue =
renderValue.isBlank().conditional(o.NULL_EXPR, renderValue.callMethod('toString', []));
updateStmts.push(
renderer
.callMethod(
'setElementAttribute', [renderElement, o.literal(boundProp.name), renderValue])
.toStmt());
checkStmts.push(o.importExpr(createIdentifier(Identifiers.checkRenderAttribute))
.callFn([
view, renderElement, o.literal(boundProp.name), oldValue,
oldValue.set(evalResult.currValExpr),
evalResult.forceUpdate || o.literal(false), securityContext
])
.toStmt());
break;
case PropertyBindingType.Class:
updateStmts.push(
renderer
.callMethod(
'setElementClass', [renderElement, o.literal(boundProp.name), renderValue])
checkStmts.push(
o.importExpr(createIdentifier(Identifiers.checkRenderClass))
.callFn([
view, renderElement, o.literal(boundProp.name), oldValue,
oldValue.set(evalResult.currValExpr), evalResult.forceUpdate || o.literal(false)
])
.toStmt());
break;
case PropertyBindingType.Style:
let strValue: o.Expression = renderValue.callMethod('toString', []);
if (isPresent(boundProp.unit)) {
strValue = strValue.plus(o.literal(boundProp.unit));
}
renderValue = renderValue.isBlank().conditional(o.NULL_EXPR, strValue);
updateStmts.push(
renderer
.callMethod(
'setElementStyle', [renderElement, o.literal(boundProp.name), renderValue])
checkStmts.push(
o.importExpr(createIdentifier(Identifiers.checkRenderStyle))
.callFn([
view, renderElement, o.literal(boundProp.name), o.literal(boundProp.unit), oldValue,
oldValue.set(evalResult.currValExpr), evalResult.forceUpdate || o.literal(false),
securityContext
])
.toStmt());
break;
case PropertyBindingType.Animation:
throw new Error('Illegal state: Should not come here!');
}
return updateStmts;
return checkStmts;
}
function sanitizedValue(
view: o.Expression, boundProp: BoundElementPropertyAst, renderValue: o.Expression,
securityContextExpression?: o.Expression): o.Expression {
function calcSecurityContext(
boundProp: BoundElementPropertyAst, securityContextExpression?: o.Expression): o.Expression {
if (boundProp.securityContext === SecurityContext.NONE) {
return renderValue; // No sanitization needed.
return o.NULL_EXPR; // No sanitization needed.
}
if (!boundProp.needsRuntimeSecurityContext) {
securityContextExpression =
@ -84,15 +79,13 @@ function sanitizedValue(
if (!securityContextExpression) {
throw new Error(`internal error, no SecurityContext given ${boundProp.name}`);
}
const ctx = view.prop('viewUtils').prop('sanitizer');
const args = [securityContextExpression, renderValue];
return ctx.callMethod('sanitize', args);
return securityContextExpression;
}
export function triggerAnimation(
export function createCheckAnimationBindingStmts(
view: o.Expression, componentView: o.Expression, boundProp: BoundElementPropertyAst,
boundOutputs: BoundEventAst[], eventListener: o.Expression, renderElement: o.Expression,
renderValue: o.Expression, lastRenderValue: o.Expression) {
oldValue: o.ReadPropExpr, evalResult: ConvertPropertyBindingResult) {
const detachStmts: o.Statement[] = [];
const updateStmts: o.Statement[] = [];
@ -104,22 +97,21 @@ export function triggerAnimation(
// it's important to normalize the void value as `void` explicitly
// so that the styles data can be obtained from the stringmap
const emptyStateValue = o.literal(EMPTY_ANIMATION_STATE);
const unitializedValue = o.importExpr(createIdentifier(Identifiers.UNINITIALIZED));
const animationTransitionVar = o.variable('animationTransition_' + animationName);
updateStmts.push(
animationTransitionVar
.set(animationFnExpr.callFn([
view, renderElement,
lastRenderValue.equals(unitializedValue).conditional(emptyStateValue, lastRenderValue),
renderValue.equals(unitializedValue).conditional(emptyStateValue, renderValue)
view, renderElement, isFirstViewCheck(view).conditional(emptyStateValue, oldValue),
evalResult.currValExpr
]))
.toDeclStmt());
updateStmts.push(oldValue.set(evalResult.currValExpr).toStmt());
detachStmts.push(
animationTransitionVar
.set(animationFnExpr.callFn([view, renderElement, lastRenderValue, emptyStateValue]))
.toDeclStmt());
detachStmts.push(animationTransitionVar
.set(animationFnExpr.callFn(
[view, renderElement, evalResult.currValExpr, emptyStateValue]))
.toDeclStmt());
const registerStmts: o.Statement[] = [];
const animationStartMethodExists = boundOutputs.find(
@ -151,5 +143,14 @@ export function triggerAnimation(
updateStmts.push(...registerStmts);
detachStmts.push(...registerStmts);
return {updateStmts, detachStmts};
const checkUpdateStmts: o.Statement[] = [
...evalResult.stmts,
new o.IfStmt(
o.importExpr(createIdentifier(Identifiers.checkBinding)).callFn([
view, oldValue, evalResult.currValExpr, evalResult.forceUpdate || o.literal(false)
]),
updateStmts)
];
const checkDetachStmts: o.Statement[] = [...evalResult.stmts, ...detachStmts];
return {checkUpdateStmts, checkDetachStmts};
}

View File

@ -7,9 +7,9 @@
*/
import {CompileDirectiveMetadata, CompileDirectiveSummary, CompileIdentifierMetadata, dirWrapperClassName, identifierModuleUrl, identifierName} from './compile_metadata';
import {createCheckBindingField, createCheckBindingStmt} from './compiler_util/binding_util';
import {createCheckBindingField, isFirstViewCheck} from './compiler_util/binding_util';
import {EventHandlerVars, convertActionBinding, convertPropertyBinding} from './compiler_util/expression_converter';
import {triggerAnimation, writeToRenderer} from './compiler_util/render_util';
import {createCheckAnimationBindingStmts, createCheckRenderBindingStmt} from './compiler_util/render_util';
import {CompilerConfig} from './config';
import {Parser} from './expression_parser/parser';
import {Identifiers, createIdentifier} from './identifiers';
@ -32,8 +32,8 @@ const CHANGES_FIELD_NAME = '_changes';
const CHANGED_FIELD_NAME = '_changed';
const EVENT_HANDLER_FIELD_NAME = '_eventHandler';
const CHANGE_VAR = o.variable('change');
const CURR_VALUE_VAR = o.variable('currValue');
const THROW_ON_CHANGE_VAR = o.variable('throwOnChange');
const FORCE_UPDATE_VAR = o.variable('forceUpdate');
const VIEW_VAR = o.variable('view');
const COMPONENT_VIEW_VAR = o.variable('componentView');
@ -130,8 +130,9 @@ class DirectiveWrapperBuilder implements ClassBuilder {
new o.ClassField(CONTEXT_FIELD_NAME, o.importType(this.dirMeta.type)),
new o.ClassField(CHANGED_FIELD_NAME, o.BOOL_TYPE, [o.StmtModifier.Private]),
];
const ctorStmts: o.Statement[] =
[o.THIS_EXPR.prop(CHANGED_FIELD_NAME).set(o.literal(false)).toStmt()];
const ctorStmts: o.Statement[] = [
o.THIS_EXPR.prop(CHANGED_FIELD_NAME).set(o.literal(false)).toStmt(),
];
if (this.genChanges) {
fields.push(new o.ClassField(
CHANGES_FIELD_NAME, new o.MapType(o.DYNAMIC_TYPE), [o.StmtModifier.Private]));
@ -180,14 +181,14 @@ function addNgDoCheckMethod(builder: DirectiveWrapperBuilder) {
if (builder.ngOnInit) {
lifecycleStmts.push(new o.IfStmt(
VIEW_VAR.prop('numberOfChecks').identical(new o.LiteralExpr(0)),
isFirstViewCheck(VIEW_VAR),
[o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).callMethod('ngOnInit', []).toStmt()]));
}
if (builder.ngDoCheck) {
lifecycleStmts.push(o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).callMethod('ngDoCheck', []).toStmt());
}
if (lifecycleStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(THROW_ON_CHANGE_VAR), lifecycleStmts));
stmts.push(new o.IfStmt(o.not(VIEW_VAR.prop('throwOnChange')), lifecycleStmts));
}
stmts.push(new o.ReturnStatement(changedVar));
@ -197,7 +198,6 @@ function addNgDoCheckMethod(builder: DirectiveWrapperBuilder) {
new o.FnParam(
VIEW_VAR.name, o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(RENDER_EL_VAR.name, o.DYNAMIC_TYPE),
new o.FnParam(THROW_ON_CHANGE_VAR.name, o.BOOL_TYPE),
],
stmts, o.BOOL_TYPE));
}
@ -207,24 +207,35 @@ function addCheckInputMethod(input: string, builder: DirectiveWrapperBuilder) {
const onChangeStatements: o.Statement[] = [
o.THIS_EXPR.prop(CHANGED_FIELD_NAME).set(o.literal(true)).toStmt(),
o.THIS_EXPR.prop(CONTEXT_FIELD_NAME).prop(input).set(CURR_VALUE_VAR).toStmt(),
field.expression.set(CURR_VALUE_VAR).toStmt()
];
let methodBody: o.Statement[];
if (builder.genChanges) {
onChangeStatements.push(o.THIS_EXPR.prop(CHANGES_FIELD_NAME)
.key(o.literal(input))
.set(o.importExpr(createIdentifier(Identifiers.SimpleChange))
.instantiate([field.expression, CURR_VALUE_VAR]))
.toStmt());
onChangeStatements.push(
o.THIS_EXPR.prop(CHANGES_FIELD_NAME).key(o.literal(input)).set(CHANGE_VAR).toStmt());
methodBody = [
CHANGE_VAR
.set(o.importExpr(createIdentifier(Identifiers.checkBindingChange)).callFn([
VIEW_VAR, field.expression, CURR_VALUE_VAR, FORCE_UPDATE_VAR
]))
.toDeclStmt(),
new o.IfStmt(CHANGE_VAR, onChangeStatements)
];
} else {
methodBody = [new o.IfStmt(
o.importExpr(createIdentifier(Identifiers.checkBinding)).callFn([
VIEW_VAR, field.expression, CURR_VALUE_VAR, FORCE_UPDATE_VAR
]),
onChangeStatements)];
}
const methodBody: o.Statement[] = createCheckBindingStmt(
{currValExpr: CURR_VALUE_VAR, forceUpdate: FORCE_UPDATE_VAR, stmts: []}, field.expression,
THROW_ON_CHANGE_VAR, onChangeStatements);
builder.methods.push(new o.ClassMethod(
`check_${input}`,
[
new o.FnParam(
VIEW_VAR.name, o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(CURR_VALUE_VAR.name, o.DYNAMIC_TYPE),
new o.FnParam(THROW_ON_CHANGE_VAR.name, o.BOOL_TYPE),
new o.FnParam(FORCE_UPDATE_VAR.name, o.BOOL_TYPE),
new o.FnParam(FORCE_UPDATE_VAR.name, o.BOOL_TYPE)
],
methodBody));
}
@ -240,7 +251,6 @@ function addCheckHostMethod(
COMPONENT_VIEW_VAR.name,
o.importType(createIdentifier(Identifiers.AppView), [o.DYNAMIC_TYPE])),
new o.FnParam(RENDER_EL_VAR.name, o.DYNAMIC_TYPE),
new o.FnParam(THROW_ON_CHANGE_VAR.name, o.BOOL_TYPE),
];
hostProps.forEach((hostProp, hostPropIdx) => {
const field = createCheckBindingField(builder);
@ -255,23 +265,18 @@ function addCheckHostMethod(
methodParams.push(new o.FnParam(
securityContextExpr.name, o.importType(createIdentifier(Identifiers.SecurityContext))));
}
let checkBindingStmts: o.Statement[];
if (hostProp.isAnimation) {
const {updateStmts, detachStmts} = triggerAnimation(
const {checkUpdateStmts, checkDetachStmts} = createCheckAnimationBindingStmts(
VIEW_VAR, COMPONENT_VIEW_VAR, hostProp, hostEvents,
o.THIS_EXPR.prop(EVENT_HANDLER_FIELD_NAME)
.or(o.importExpr(createIdentifier(Identifiers.noop))),
RENDER_EL_VAR, evalResult.currValExpr, field.expression);
checkBindingStmts = updateStmts;
builder.detachStmts.push(...detachStmts);
RENDER_EL_VAR, field.expression, evalResult);
builder.detachStmts.push(...checkDetachStmts);
stmts.push(...checkUpdateStmts);
} else {
checkBindingStmts = writeToRenderer(
VIEW_VAR, hostProp, RENDER_EL_VAR, evalResult.currValExpr,
builder.compilerConfig.logBindingUpdate, securityContextExpr);
stmts.push(...createCheckRenderBindingStmt(
VIEW_VAR, RENDER_EL_VAR, hostProp, field.expression, evalResult, securityContextExpr));
}
stmts.push(...createCheckBindingStmt(
evalResult, field.expression, THROW_ON_CHANGE_VAR, checkBindingStmts));
});
builder.methods.push(new o.ClassMethod('checkHost', methodParams, stmts));
}
@ -381,20 +386,19 @@ export class DirectiveWrapperExpressions {
return dirWrapper.prop(CONTEXT_FIELD_NAME);
}
static ngDoCheck(
dirWrapper: o.Expression, view: o.Expression, renderElement: o.Expression,
throwOnChange: o.Expression): o.Expression {
return dirWrapper.callMethod('ngDoCheck', [view, renderElement, throwOnChange]);
static ngDoCheck(dirWrapper: o.Expression, view: o.Expression, renderElement: o.Expression, ):
o.Expression {
return dirWrapper.callMethod('ngDoCheck', [view, renderElement]);
}
static checkHost(
hostProps: BoundElementPropertyAst[], dirWrapper: o.Expression, view: o.Expression,
componentView: o.Expression, renderElement: o.Expression, throwOnChange: o.Expression,
componentView: o.Expression, renderElement: o.Expression,
runtimeSecurityContexts: o.Expression[]): o.Statement[] {
if (hostProps.length) {
return [dirWrapper
.callMethod(
'checkHost', [view, componentView, renderElement, throwOnChange].concat(
runtimeSecurityContexts))
'checkHost',
[view, componentView, renderElement].concat(runtimeSecurityContexts))
.toStmt()];
} else {
return [];

View File

@ -10,7 +10,7 @@ import {ANALYZE_FOR_ENTRY_COMPONENTS, AnimationTransitionEvent, ChangeDetectionS
import {StaticSymbol} from './aot/static_symbol';
import {CompileIdentifierMetadata, CompileTokenMetadata, identifierModuleUrl, identifierName} from './compile_metadata';
import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AnimationTransition, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, ComponentRef_, DebugAppView, DebugContext, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, ValueUnwrapper, ViewContainer, ViewType, balanceAnimationKeyframes, clearStyles, collectAndResolveStyles, devModeEqual, prepareFinalAnimationStyles, reflector, registerModuleFactory, renderStyles, view_utils} from './private_import_core';
import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AnimationTransition, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, ComponentRef_, DebugAppView, DebugContext, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, ValueUnwrapper, ViewContainer, ViewType, balanceAnimationKeyframes, clearStyles, collectAndResolveStyles, devModeEqual, prepareFinalAnimationStyles, reflector, registerModuleFactory, renderStyles, view_utils} from './private_import_core';
const APP_VIEW_MODULE_URL = assetUrl('core', 'linker/view');
const VIEW_UTILS_MODULE_URL = assetUrl('core', 'linker/view_utils');
@ -161,8 +161,6 @@ export class Identifiers {
};
static SimpleChange:
IdentifierSpec = {name: 'SimpleChange', moduleUrl: CD_MODULE_URL, runtime: SimpleChange};
static UNINITIALIZED:
IdentifierSpec = {name: 'UNINITIALIZED', moduleUrl: CD_MODULE_URL, runtime: UNINITIALIZED};
static ChangeDetectorStatus: IdentifierSpec = {
name: 'ChangeDetectorStatus',
moduleUrl: CD_MODULE_URL,
@ -173,6 +171,36 @@ export class Identifiers {
moduleUrl: VIEW_UTILS_MODULE_URL,
runtime: view_utils.checkBinding
};
static checkBindingChange: IdentifierSpec = {
name: 'checkBindingChange',
moduleUrl: VIEW_UTILS_MODULE_URL,
runtime: view_utils.checkBindingChange
};
static checkRenderText: IdentifierSpec = {
name: 'checkRenderText',
moduleUrl: VIEW_UTILS_MODULE_URL,
runtime: view_utils.checkRenderText
};
static checkRenderProperty: IdentifierSpec = {
name: 'checkRenderProperty',
moduleUrl: VIEW_UTILS_MODULE_URL,
runtime: view_utils.checkRenderProperty
};
static checkRenderAttribute: IdentifierSpec = {
name: 'checkRenderAttribute',
moduleUrl: VIEW_UTILS_MODULE_URL,
runtime: view_utils.checkRenderAttribute
};
static checkRenderClass: IdentifierSpec = {
name: 'checkRenderClass',
moduleUrl: VIEW_UTILS_MODULE_URL,
runtime: view_utils.checkRenderClass
};
static checkRenderStyle: IdentifierSpec = {
name: 'checkRenderStyle',
moduleUrl: VIEW_UTILS_MODULE_URL,
runtime: view_utils.checkRenderStyle
};
static devModeEqual:
IdentifierSpec = {name: 'devModeEqual', moduleUrl: CD_MODULE_URL, runtime: devModeEqual};
static inlineInterpolate: IdentifierSpec = {

View File

@ -32,7 +32,6 @@ export const view_utils: typeof r.view_utils = r.view_utils;
export const DebugContext: typeof r.DebugContext = r.DebugContext;
export const StaticNodeDebugInfo: typeof r.StaticNodeDebugInfo = r.StaticNodeDebugInfo;
export const devModeEqual: typeof r.devModeEqual = r.devModeEqual;
export const UNINITIALIZED: typeof r.UNINITIALIZED = r.UNINITIALIZED;
export const ValueUnwrapper: typeof r.ValueUnwrapper = r.ValueUnwrapper;
export const TemplateRef_: typeof r.TemplateRef_ = r.TemplateRef_;
export type RenderDebugInfo = typeof r._RenderDebugInfo;

View File

@ -9,7 +9,6 @@
import {AnimationEntryCompileResult} from '../animation/animation_compiler';
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeSummary, tokenName, viewClassName} from '../compile_metadata';
import {EventHandlerVars, NameResolver} from '../compiler_util/expression_converter';
import {createPureProxy} from '../compiler_util/identifier_util';
import {CompilerConfig} from '../config';
import {isPresent} from '../facade/lang';
import {Identifiers, createIdentifier} from '../identifiers';

View File

@ -47,6 +47,7 @@ export class ViewConstructorVars {
export class ViewProperties {
static renderer = o.THIS_EXPR.prop('renderer');
static viewUtils = o.THIS_EXPR.prop('viewUtils');
static throwOnChange = o.THIS_EXPR.prop('throwOnChange');
}
export class InjectMethodVars {
@ -54,9 +55,3 @@ export class InjectMethodVars {
static requestNodeIndex = o.variable('requestNodeIndex');
static notFoundResult = o.variable('notFoundResult');
}
export class DetectChangesVars {
static throwOnChange = o.variable(`throwOnChange`);
static changes = o.variable(`changes`);
static changed = o.variable(`changed`);
}

View File

@ -7,6 +7,7 @@
*/
import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata';
import {isFirstViewCheck} from '../compiler_util/binding_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import * as o from '../output/output_ast';
import {LifecycleHooks} from '../private_import_core';
@ -14,10 +15,6 @@ import {DirectiveAst, ProviderAst, ProviderAstType} from '../template_parser/tem
import {CompileElement} from './compile_element';
import {CompileView} from './compile_view';
import {DetectChangesVars} from './constants';
const STATE_IS_NEVER_CHECKED = o.THIS_EXPR.prop('numberOfChecks').identical(new o.LiteralExpr(0));
const NOT_THROW_ON_CHANGES = o.not(DetectChangesVars.throwOnChange);
export function bindDirectiveAfterContentLifecycleCallbacks(
directiveMeta: CompileDirectiveSummary, directiveInstance: o.Expression,
@ -29,7 +26,8 @@ export function bindDirectiveAfterContentLifecycleCallbacks(
compileElement.nodeIndex, compileElement.sourceAst);
if (lifecycleHooks.indexOf(LifecycleHooks.AfterContentInit) !== -1) {
afterContentLifecycleCallbacksMethod.addStmt(new o.IfStmt(
STATE_IS_NEVER_CHECKED, [directiveInstance.callMethod('ngAfterContentInit', []).toStmt()]));
isFirstViewCheck(o.THIS_EXPR),
[directiveInstance.callMethod('ngAfterContentInit', []).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.AfterContentChecked) !== -1) {
afterContentLifecycleCallbacksMethod.addStmt(
@ -47,7 +45,8 @@ export function bindDirectiveAfterViewLifecycleCallbacks(
compileElement.nodeIndex, compileElement.sourceAst);
if (lifecycleHooks.indexOf(LifecycleHooks.AfterViewInit) !== -1) {
afterViewLifecycleCallbacksMethod.addStmt(new o.IfStmt(
STATE_IS_NEVER_CHECKED, [directiveInstance.callMethod('ngAfterViewInit', []).toStmt()]));
isFirstViewCheck(o.THIS_EXPR),
[directiveInstance.callMethod('ngAfterViewInit', []).toStmt()]));
}
if (lifecycleHooks.indexOf(LifecycleHooks.AfterViewChecked) !== -1) {
afterViewLifecycleCallbacksMethod.addStmt(

View File

@ -8,19 +8,19 @@
import {SecurityContext} from '@angular/core';
import {createCheckBindingField, createCheckBindingStmt} from '../compiler_util/binding_util';
import {createCheckBindingField} from '../compiler_util/binding_util';
import {ConvertPropertyBindingResult, convertPropertyBinding} from '../compiler_util/expression_converter';
import {createEnumExpression} from '../compiler_util/identifier_util';
import {triggerAnimation, writeToRenderer} from '../compiler_util/render_util';
import {createCheckAnimationBindingStmts, createCheckRenderBindingStmt} from '../compiler_util/render_util';
import {DirectiveWrapperExpressions} from '../directive_wrapper_compiler';
import {Identifiers, createIdentifier} from '../identifiers';
import * as o from '../output/output_ast';
import {isDefaultChangeDetectionStrategy} from '../private_import_core';
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
import {BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, PropertyBindingType} from '../template_parser/template_ast';
import {CompileElement, CompileNode} from './compile_element';
import {CompileView} from './compile_view';
import {DetectChangesVars} from './constants';
import {getHandleEventMethodName} from './util';
export function bindRenderText(
@ -33,11 +33,15 @@ export function bindRenderText(
}
view.detectChangesRenderPropertiesMethod.resetDebugInfo(compileNode.nodeIndex, boundText);
view.detectChangesRenderPropertiesMethod.addStmts(createCheckBindingStmt(
evalResult, valueField.expression, DetectChangesVars.throwOnChange,
[o.THIS_EXPR.prop('renderer')
.callMethod('setText', [compileNode.renderNode, evalResult.currValExpr])
.toStmt()]));
view.detectChangesRenderPropertiesMethod.addStmts(evalResult.stmts);
view.detectChangesRenderPropertiesMethod.addStmt(
o.importExpr(createIdentifier(Identifiers.checkRenderText))
.callFn([
o.THIS_EXPR, compileNode.renderNode, valueField.expression,
valueField.expression.set(evalResult.currValExpr),
evalResult.forceUpdate || o.literal(false)
])
.toStmt());
}
export function bindRenderInputs(
@ -54,31 +58,27 @@ export function bindRenderInputs(
if (!evalResult) {
return;
}
const checkBindingStmts: o.Statement[] = [];
let compileMethod = view.detectChangesRenderPropertiesMethod;
switch (boundProp.type) {
case PropertyBindingType.Property:
case PropertyBindingType.Attribute:
case PropertyBindingType.Class:
case PropertyBindingType.Style:
checkBindingStmts.push(...writeToRenderer(
o.THIS_EXPR, boundProp, renderNode, evalResult.currValExpr,
view.genConfig.logBindingUpdate));
compileMethod.addStmts(createCheckRenderBindingStmt(
o.THIS_EXPR, renderNode, boundProp, bindingField.expression, evalResult));
break;
case PropertyBindingType.Animation:
compileMethod = view.animationBindingsMethod;
const {updateStmts, detachStmts} = triggerAnimation(
const {checkUpdateStmts, checkDetachStmts} = createCheckAnimationBindingStmts(
o.THIS_EXPR, o.THIS_EXPR, boundProp, boundOutputs,
(hasEvents ? o.THIS_EXPR.prop(getHandleEventMethodName(compileElement.nodeIndex)) :
o.importExpr(createIdentifier(Identifiers.noop)))
.callMethod(o.BuiltinMethod.Bind, [o.THIS_EXPR]),
compileElement.renderNode, evalResult.currValExpr, bindingField.expression);
checkBindingStmts.push(...updateStmts);
view.detachMethod.addStmts(detachStmts);
compileElement.renderNode, bindingField.expression, evalResult);
view.detachMethod.addStmts(checkDetachStmts);
compileMethod.addStmts(checkUpdateStmts);
break;
}
compileMethod.addStmts(createCheckBindingStmt(
evalResult, bindingField.expression, DetectChangesVars.throwOnChange, checkBindingStmts));
});
}
@ -108,7 +108,7 @@ export function bindDirectiveHostProps(
DirectiveWrapperExpressions.checkHost(
directiveAst.hostProperties, directiveWrapperInstance, o.THIS_EXPR,
compileElement.compViewExpr || o.THIS_EXPR, compileElement.renderNode,
DetectChangesVars.throwOnChange, runtimeSecurityCtxExprs));
runtimeSecurityCtxExprs));
}
export function bindDirectiveInputs(
@ -132,17 +132,13 @@ export function bindDirectiveInputs(
directiveWrapperInstance
.callMethod(
`check_${input.directiveName}`,
[
evalResult.currValExpr, DetectChangesVars.throwOnChange,
evalResult.forceUpdate || o.literal(false)
])
[o.THIS_EXPR, evalResult.currValExpr, evalResult.forceUpdate || o.literal(false)])
.toStmt());
});
const isOnPushComp = directiveAst.directive.isComponent &&
!isDefaultChangeDetectionStrategy(directiveAst.directive.changeDetection);
const directiveDetectChangesExpr = DirectiveWrapperExpressions.ngDoCheck(
directiveWrapperInstance, o.THIS_EXPR, compileElement.renderNode,
DetectChangesVars.throwOnChange);
directiveWrapperInstance, o.THIS_EXPR, compileElement.renderNode);
const directiveDetectChangesStmt = isOnPushComp ?
new o.IfStmt(
directiveDetectChangesExpr,

View File

@ -21,7 +21,7 @@ import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventA
import {CompileElement, CompileNode} from './compile_element';
import {CompileView, CompileViewRootNode, CompileViewRootNodeType} from './compile_view';
import {ChangeDetectorStatusEnum, DetectChangesVars, InjectMethodVars, ViewConstructorVars, ViewEncapsulationEnum, ViewProperties, ViewTypeEnum} from './constants';
import {ChangeDetectorStatusEnum, InjectMethodVars, ViewConstructorVars, ViewEncapsulationEnum, ViewProperties, ViewTypeEnum} from './constants';
import {ComponentFactoryDependency, ComponentViewDependency, DirectiveWrapperDependency} from './deps';
const IMPLICIT_TEMPLATE_VAR = '\$implicit';
@ -483,9 +483,7 @@ function createViewClass(
],
addReturnValuefNotEmpty(view.injectorGetMethod.finish(), InjectMethodVars.notFoundResult),
o.DYNAMIC_TYPE),
new o.ClassMethod(
'detectChangesInternal', [new o.FnParam(DetectChangesVars.throwOnChange.name, o.BOOL_TYPE)],
generateDetectChangesMethod(view)),
new o.ClassMethod('detectChangesInternal', [], generateDetectChangesMethod(view)),
new o.ClassMethod('dirtyParentQueriesInternal', [], view.dirtyParentQueriesMethod.finish()),
new o.ClassMethod('destroyInternal', [], generateDestroyMethod(view)),
new o.ClassMethod('detachInternal', [], view.detachMethod.finish()),
@ -569,36 +567,26 @@ function generateDetectChangesMethod(view: CompileView): o.Statement[] {
stmts.push(...view.detectChangesInInputsMethod.finish());
view.viewContainers.forEach((viewContainer) => {
stmts.push(
viewContainer.callMethod('detectChangesInNestedViews', [DetectChangesVars.throwOnChange])
viewContainer.callMethod('detectChangesInNestedViews', [ViewProperties.throwOnChange])
.toStmt());
});
const afterContentStmts = view.updateContentQueriesMethod.finish().concat(
view.afterContentLifecycleCallbacksMethod.finish());
if (afterContentStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(DetectChangesVars.throwOnChange), afterContentStmts));
stmts.push(new o.IfStmt(o.not(ViewProperties.throwOnChange), afterContentStmts));
}
stmts.push(...view.detectChangesRenderPropertiesMethod.finish());
view.viewChildren.forEach((viewChild) => {
stmts.push(
viewChild.callMethod('internalDetectChanges', [DetectChangesVars.throwOnChange]).toStmt());
viewChild.callMethod('internalDetectChanges', [ViewProperties.throwOnChange]).toStmt());
});
const afterViewStmts =
view.updateViewQueriesMethod.finish().concat(view.afterViewLifecycleCallbacksMethod.finish());
if (afterViewStmts.length > 0) {
stmts.push(new o.IfStmt(o.not(DetectChangesVars.throwOnChange), afterViewStmts));
stmts.push(new o.IfStmt(o.not(ViewProperties.throwOnChange), afterViewStmts));
}
const varStmts: any[] = [];
const readVars = o.findReadVarNames(stmts);
if (readVars.has(DetectChangesVars.changed.name)) {
varStmts.push(DetectChangesVars.changed.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE));
}
if (readVars.has(DetectChangesVars.changes.name)) {
varStmts.push(
DetectChangesVars.changes.set(o.NULL_EXPR)
.toDeclStmt(new o.MapType(o.importType(createIdentifier(Identifiers.SimpleChange)))));
}
varStmts.push(...createSharedBindingVariablesIfNeeded(stmts));
const varStmts = createSharedBindingVariablesIfNeeded(stmts);
return varStmts.concat(stmts);
}