Angular2 何时检查模板值?它如何影响性能? [...]="complexMethod()"
When does Angular2 examine template values? How does it impact performance? [...]="complexMethod()"
我们有一个 Angular2 应用程序。
我为一组复选框创建了一个通用组件。
由于它应该是通用的,即处理一组相同 (TypeScript) 的任何对象 class,我选择模拟 Wicket 中已知的模型适配器方法。不完全是,因为我没有将它包装在 class 中,而是传递了单独的回调:
<wu-checkboxes [groupName]="'includedApps'"
[options]="availableApps"
[valueCallback]="appsValueCallback"
[labelCallback]="appsLabelCallback"
[equalsCallback]="equalsCallback"
[(checkedOptions)]="applicationGroup.applications"
(checkedOptionsChange)="onCheckedOptionsChange()"
>
</wu-checkboxes>
回调看起来像这样:
appsValueCallback = (app: RegisteredApplication) => ""+app.id;
appsLabelCallback = (app: RegisteredApplication) => app.title;
equalsCallback = (a1: RegisteredApplication, a2: RegisteredApplication) => a1.id === a2.id;
availableApps: RegisteredApplication[];
includedApps: RegisteredApplication[];
组件本身有这个:
<div *ngFor="let option of _options">
<label>
<input type="checkbox" [name]="groupName"
[value]="valueCallback(option)"
[checked]="shouldBeChecked(option)"
(change)="handleCheckboxChange(option, $event)"
/>
{{labelCallback(option)}}
</label>
</div>
和
shouldBeChecked(option: ItemType): boolean {
console.log("shouldBeChecked() called.", option, this.checkedOptions);
return ...
}
我希望每个复选框只调用一次。
但是在控制台中,我看到 shouldBeChecked()
被调用了几十次 即使在初始渲染期间只有一个复选框。我检查过 ngAfterViewChecked
和 ngAfterViewChanged
只为复选框组件调用一次。
TLDR:
- 为什么 Angular2 调用 shouldBeChecked 这么多次?
- 这是否表示组件、页面或应用程序的设置有误?
- 我应该如何找出来电的原因?堆栈跟踪对我来说用处不大。
这样想 - (我过度简化以专注于您的特定问题)Angular 的更改检测通过侦听异步事件(按键、点击、ajax 请求等)并且每当 Angular 收到这样的事件时,它就知道变量绑定可能已更改。因此,它遍历所有绑定以检查值是否已更改。
这意味着如果您要绑定到函数调用的结果,检查绑定是否已更改的唯一方法是调用函数并检查结果。它在每个更改检测周期(即每次触发异步事件时)都执行此操作。
(同样,这是对正在发生的事情的过度简化,但它说明了 Angular 每次需要检查绑定是否已更改时都必须调用该函数的要点。
PS。从您的角度来看,让事情变得更糟的是,在开发模式下,Angular 实际上会检查每个绑定两次,作为一种错误检查步骤。因此,这只会增加您的函数被调用的次数。
我们有一个 Angular2 应用程序。
我为一组复选框创建了一个通用组件。
由于它应该是通用的,即处理一组相同 (TypeScript) 的任何对象 class,我选择模拟 Wicket 中已知的模型适配器方法。不完全是,因为我没有将它包装在 class 中,而是传递了单独的回调:
<wu-checkboxes [groupName]="'includedApps'"
[options]="availableApps"
[valueCallback]="appsValueCallback"
[labelCallback]="appsLabelCallback"
[equalsCallback]="equalsCallback"
[(checkedOptions)]="applicationGroup.applications"
(checkedOptionsChange)="onCheckedOptionsChange()"
>
</wu-checkboxes>
回调看起来像这样:
appsValueCallback = (app: RegisteredApplication) => ""+app.id;
appsLabelCallback = (app: RegisteredApplication) => app.title;
equalsCallback = (a1: RegisteredApplication, a2: RegisteredApplication) => a1.id === a2.id;
availableApps: RegisteredApplication[];
includedApps: RegisteredApplication[];
组件本身有这个:
<div *ngFor="let option of _options">
<label>
<input type="checkbox" [name]="groupName"
[value]="valueCallback(option)"
[checked]="shouldBeChecked(option)"
(change)="handleCheckboxChange(option, $event)"
/>
{{labelCallback(option)}}
</label>
</div>
和
shouldBeChecked(option: ItemType): boolean {
console.log("shouldBeChecked() called.", option, this.checkedOptions);
return ...
}
我希望每个复选框只调用一次。
但是在控制台中,我看到 shouldBeChecked()
被调用了几十次 即使在初始渲染期间只有一个复选框。我检查过 ngAfterViewChecked
和 ngAfterViewChanged
只为复选框组件调用一次。
TLDR:
- 为什么 Angular2 调用 shouldBeChecked 这么多次?
- 这是否表示组件、页面或应用程序的设置有误?
- 我应该如何找出来电的原因?堆栈跟踪对我来说用处不大。
这样想 - (我过度简化以专注于您的特定问题)Angular 的更改检测通过侦听异步事件(按键、点击、ajax 请求等)并且每当 Angular 收到这样的事件时,它就知道变量绑定可能已更改。因此,它遍历所有绑定以检查值是否已更改。
这意味着如果您要绑定到函数调用的结果,检查绑定是否已更改的唯一方法是调用函数并检查结果。它在每个更改检测周期(即每次触发异步事件时)都执行此操作。
(同样,这是对正在发生的事情的过度简化,但它说明了 Angular 每次需要检查绑定是否已更改时都必须调用该函数的要点。
PS。从您的角度来看,让事情变得更糟的是,在开发模式下,Angular 实际上会检查每个绑定两次,作为一种错误检查步骤。因此,这只会增加您的函数被调用的次数。