Angular2 zone.run()vs ChangeDetectorRef.detectChanges()

时间:2017-03-23 09:24:12

标签: javascript angular angular2-changedetection

假设我的service.ts中有import { Component } from "@angular/core"; import { UserService } from '..' // import the service where you stored it. @Component({ selector: "team", templateUrl: "../Scripts/components/team/team.component.html" }) export class TeamComponent implements OnInit { public users: IUserID[]; constructor(private _userService: UserService) { } } ngOnInit() { this._getUserData(); } private _getUserData() { this._userService.getUserData(userId) // pass the userId here. you can get it from the router params or somewhere else. .subscribe(response => { if(response){ this.users = <IUserID>response.json(); } }, error => console.log(error)) // handle errors the way you like. } interface IUserID { Login: string; } 超出了角度的上下文。 function noificationHandler()由第三方调用,noificationHandler()基本上使用数组并将数组发送给已订阅其服务的组件。

service.ts

noificationHandler()

component.ts

    public mySubject: Subject<any> = new Subject();
    public myObservable = this.mySubject.asObservable();

    constructor() {
       this.registry.subscribe("notification.msg",this.noificationHandler.bind(this));
    }

    noificationHandler(data) {
       this.publishUpdate(data)
    }

    publishUpdate(data) {
       this.mySubject.next(data);
    }
此时

^^^模板未使用新数据更新

由于constructor(private service: myService) { this.service.myObservable.subscribe(list => { this.list = list; }); } 在角度区域之外,因此有角度

调用此事件"notification.msg"时,不会运行更改检测。

现在有两种方法可以调用变更检测。

1)将("notification.msg")包裹在angular的zone.run()

noificationHandler()

2)通过单独要求组件检测更改

 this.registry.subscribe("a2mevent.notification.msg", this.ngZone.run(() => this.noificationHandler.bind(this)));

这两个选项都有效! 我的组件结构如下

constructor(private service: myService, private ref: ChangeDetectorRef) {
    this.service.myObservable.subscribe(list => {
        this.list = list;
        this.ref.detectChanges(); // <==== manually invoking change detection
    });
}

问题 -

1)detectChanges()是否仅检测其自身组件的更改,还是会对子组件运行更改检测?

2)zone.run()会触发从根到叶子的所有组件的变化检测吗?

在zone.run()和detectChanges()中,我很好奇性能哪个更好?

2 个答案:

答案 0 :(得分:26)

ApplicationRef.tick(与setTimeout()相同),zone.run()会导致整个应用程序发生更改检测。此外,在Angular或Angular中添加的事件侦听器(使用视图绑定或@HostBinding()导致整个应用程序的更改检测。

ChangeDetectorRef.detectChanges运行特定组件的变更检测(如果适用,则为其后代,例如由于输入绑定)

如果在Angular的区域外运行的某些代码调用Angular的代码并更改状态,则需要显式调用更改检测,因为Angular无法知道状态发生了变化。

如果对状态的更改对于组件是本地的(例如组件字段),则ChangeDetectorRef.detectChangesChangeDetectorRef.markforCheck更有效。

如果来自外部的呼叫例如导航到不同的路由,这可能会对许多组件产生影响,并且还不清楚整个路由更改何时完成,因为它可能导致异步调用(以及调用回调) 。 在这种情况下,zone.run()是更好的选择,因为直接和间接调用的代码(如observable和promises的回调)将在Angular的区域内运行,Angular将识别它们并自动调用更改检测。

答案 1 :(得分:6)

两者都完全不同。

NgZone是一个为您的应用提供区域的库,因此您可以将实例运行到多个范围。

ChangeDetection始终从父级到叶级 A&gt; B> C 当你调用detectChanges()时,它也会调用当前组件及其子组件。因此,这是对叶子组件使用OnPush changesdetectionStrategy的最佳方法,因此它们只会在更新输入时检测更改。

此外,ApplicationRef与ChangeDetector类似;区别在于它将检测从根组件到最后一个子组件的更改。

ChaneDetection和NgZone是最好的组合,总是避免不必要的ChangeDetection