我的应用程序结构如下所示:
ts:
...
export class TodoListComponent {
get sortedTodos():ITodo[] {
console.log(this.counter++);
...
}
....
Run Code Online (Sandbox Code Playgroud)
的HTML:
<div class="todo-item" *ngFor="let todo of sortedTodos" [class.completed]="todo.completed">
<todo-list-item [todo]="todo" class="todo-item" (deleted)="onTodoDeleted(todo)"
(toggled)="onTodoUpdated($event)"></todo-list-item>
</div>
Run Code Online (Sandbox Code Playgroud)
如果我启动应用程序,我会在控制台中看到:
1
2
3
4
5
6
Run Code Online (Sandbox Code Playgroud)
我真的对此行为感到困惑。对我来说,它看起来很奇怪,我认为它可能会导致错误和性能问题。请解释为什么执行6!一次加载页面的次数。
我不确定我是否提供了主题中所有需要的信息。随意提出其他要求。也可以找到所有代码库bitbucket回购链接
聚苯乙烯
完整的ts文件内容:
import {Component, Input, Output, EventEmitter} from "@angular/core"
import {ITodo} from "../../shared/todo.model";
import {TodoService} from "../../shared/todoService";
@Component({
moduleId: module.id,
selector: "todo-list",
templateUrl: "todo-list.component.html",
styleUrls: ["todo-list.component.css"],
})
export class TodoListComponent {
@Input() todos:ITodo[];
@Output() updated:EventEmitter<ITodo> = new EventEmitter<ITodo>();
@Output() deleted:EventEmitter<ITodo> = new EventEmitter<ITodo>();
get sortedTodos():ITodo[] {
return !this.todos ? [] :
this.todos.map((todo:ITodo)=>todo)
.sort((a:ITodo, b:ITodo)=> {
if (a.title > b.title) {
return 1;
} else if (a.title < b.title) {
return -1;
}
return 0;
})
.sort((a:ITodo, b:ITodo)=> (+a.completed - (+b.completed)));
}
onTodoDeleted(todo:ITodo):void {
this.deleted.emit(todo);
}
onTodoUpdated(todo:ITodo):void {
this.updated.emit(todo);
}
constructor(private todoService:TodoService) {
}
}
Run Code Online (Sandbox Code Playgroud)
它执行6次,因为:
课堂上有一种tick方法,由2个变化检测周期执行3次。如果通过调用启用生产模式,它将执行3次ApplicationRefenableProdMode()
ApplicationRef是对页面上运行的Angular应用程序的引用。该tick方法从根到叶运行更改检测。
这是tick方法的外观(https://github.com/angular/angular/blob/2.3.0/modules/%40angular/core/src/application_ref.ts#L493-L509):
tick(): void {
if (this._runningTick) {
throw new Error('ApplicationRef.tick is called recursively');
}
const scope = ApplicationRef_._tickScope();
try {
this._runningTick = true;
this._views.forEach((view) => view.ref.detectChanges()); // check
if (this._enforceNoNewChanges) {
this._views.forEach((view) => view.ref.checkNoChanges()); // check only for debug mode
}
} finally {
this._runningTick = false;
wtfLeave(scope);
}
}
Run Code Online (Sandbox Code Playgroud)
对于调试模式,将 tick启动两个更改检测周期。因此detectChangesInternal在编译视图内将被调用两次。
并且由于您的sortedTodos属性是一个吸气剂,因此它将每次作为函数执行。
在此处了解更多信息(Angular 2中的变更检测)
这样我们就知道我们的sortedTodos吸气剂被两次叫一次tick
为什么该tick方法执行3次?
1)首先tick是通过引导应用程序手动运行。
private _loadComponent(componentRef: ComponentRef<any>): void {
this.attachView(componentRef.hostView);
this.tick();
Run Code Online (Sandbox Code Playgroud)
https://github.com/angular/angular/blob/2.3.0/modules/%40angular/core/src/application_ref.ts#L479
2) Angular2在zonejs中运行,因此它是管理变更检测的主要工具。上面提到的ApplicationRef已订阅zone.onMicrotaskEmpty。
this._zone.onMicrotaskEmpty.subscribe(
{next: () => { this._zone.run(() => { this.tick(); }); }});
Run Code Online (Sandbox Code Playgroud)
https://github.com/angular/angular/blob/2.3.0/modules/%40angular/core/src/application_ref.ts#L433
onMicrotaskEmpty事件是区域 稳定时的指示器
private checkStable() {
if (this._nesting == 0 && !this._hasPendingMicrotasks && !this._isStable) {
try {
this._nesting++;
this._onMicrotaskEmpty.emit(null); // notice this
} finally {
this._nesting--;
if (!this._hasPendingMicrotasks) {
try {
this.runOutsideAngular(() => this._onStable.emit(null));
} finally {
this._isStable = true;
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
https://github.com/angular/angular/blob/2.3.0/modules/%40angular/core/src/zone/ng_zone.ts#L195-L211
因此,在执行一些zonejs任务后,将触发此事件
3)您使用的是angular2-in-memory-web-api包,当您尝试获取模拟数据时,它会执行以下操作:
createConnection(req: Request): Connection {
let res = this.handleRequest(req);
let response = new Observable<Response>((responseObserver: Observer<Response>) => {
if (isSuccess(res.status)) {
responseObserver.next(res);
responseObserver.complete();
} else {
responseObserver.error(res);
}
return () => { }; // unsubscribe function
});
response = response.delay(this.config.delay || 500); // notice this
return {
readyState: ReadyState.Done,
request: req,
response
};
}
Run Code Online (Sandbox Code Playgroud)
https://github.com/angular/in-memory-web-api/blob/0.0.20/src/in-memory-backend.service.ts#L136-L155
它开始定期的zonejs任务周期,该周期使区域成为一个区域,unStable并在发出上述任务后onMicrotaskEmpty再次发出上述事件
您可以在此处找到有关zonejs的更多详细信息
总结:
因此,如您所见,您的解决方案有点错误。您不应在模板中使用getter或函数作为绑定。可能的解决方案,您可以在这里找到
| 归档时间: |
|
| 查看次数: |
2753 次 |
| 最近记录: |