gpt4 book ai didi

angular - 为什么 angular2 多次执行方法?

转载 作者:行者123 更新时间:2023-12-02 00:17:21 25 4
gpt4 key购买 nike

我的应用程序结构如下所示:

enter image description here

ts:

...
export class TodoListComponent {

get sortedTodos():ITodo[] {
console.log(this.counter++);
...
}
....

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>

如果我启动应用程序,我会在控制台中看到:

1
2
3
4
5
6

我真的对这种行为感到困惑。对我来说,它看起来很奇怪,我认为它可能会导致错误和性能问题。请解释为什么当我一次加载页面时它会执行6!次。

我不确定我是否提供了主题中所有需要的信息。请随意要求其他东西。此外,所有代码库都可以找到 bitbucket repo link

附注

完整的 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) {
}
}

最佳答案

它执行了 6 次,因为:

ApplicationRef 类中有一个 tick 方法,它通过 2 个更改检测周期执行 3 次。如果您通过调用enableProdMode()启用生产模式,它将被执行3次

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);
}
}

对于 Debug模式tick启动两个更改检测周期。因此编译 View 中的 detectChangesInternal 将被调用两次。

enter image description here

由于您的 sortedTodos 属性是一个 getter,因此它每次都会作为函数执行。

在此处了解更多相关信息 ( Change Detection in Angular 2 )

这样我们就知道我们的 sortedTodos getter 在一个 tick 内被调用两次

为什么tick方法执行了3次?

1) 第一个 tick 通过引导应用程序手动运行。

private _loadComponent(componentRef: ComponentRef<any>): void {
this.attachView(componentRef.hostView);
this.tick();

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(); }); }});

https://github.com/angular/angular/blob/2.3.0/modules/%40angular/core/src/application_ref.ts#L433

onMicrotaskEmpty 事件是 zone 稳定时的指示器

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;
}
}
}
}
}

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
};
}

https://github.com/angular/in-memory-web-api/blob/0.0.20/src/in-memory-backend.service.ts#L136-L155

它启动常规的 zonejs 任务周期,这使得区域不稳定,最后在任务执行后再次发出上述 onMicrotaskEmpty 事件

您可以在此处找到有关 zonejs 的更多详细信息

回顾:

正如您所见,您的解决方案有点错误。您不应该在模板中使用 getter 或函数作为绑定(bind)。您可以在这里找到可能的解决方案

关于angular - 为什么 angular2 多次执行方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41187667/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com