我在>= 2中有一个简单的应用程序,它使用signalr。我有一个问题,你不知道如何确定是否某些东西将在内或外执行。如果我在此路径上重新加载页面,下面的代码将用于所有signalr内容在ngzone之外。如果我在另一个完全为空的路由中加载页面&从那里导航到下面的代码,它将在ngzone中执行。
import { Component, OnInit, OnDestroy, NgZone } from '@angular/core';
import { Http } from '@angular/http';
import { Subscription } from 'rxjs/Subscription';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Component({
selector: 'app-data-page',
templateUrl: './data-page.component.html',
styleUrls: ['./data-page.component.less']
})
export class DataPageComponent implements OnInit {
constructor(private http: Http) { }
public title = 'Bug report!';
public data = new Array<any>();
private subscription: Subscription;
private connection: SignalR.Hub.Connection;
private counter:number = 1;
private secretData = new Map<number, any>();
private dataSubject = new BehaviorSubject(this.secretData);
ngOnInit() {
console.log(`ngOnInit: ${NgZone.isInAngularZone()}`);
this.subscription = this.dataSubject.subscribe((data) => {
console.log(`subscribe: ${NgZone.isInAngularZone()}`);
this.data = new Array<any>();
data.forEach((d) => {
this.data.push(d);
});
});
let uri = 'http://localhost:8080/fake/signalr';
let c = $.hubConnection(uri, { useDefaultPath: false });
this.connection = c;
c.logging = true;
let hub = c.createHubProxy('myHub');
hub.on('tick', () => {
console.log(`tick: ${NgZone.isInAngularZone()}`);
this.generateData();
});
c.start().always(() =>
{
console.log(`Calling getData: ${NgZone.isInAngularZone()}`);
hub.invoke('getData')
.always(() => {
console.log(`getData: ${NgZone.isInAngularZone()}`);
this.generateData();
});
});
// this.http.get("http://localhost:8080/fake/api/getData").subscribe(() => {
// this.generateData();
// }, (error) => {
// this.generateData();
// });
// setTimeout(() => {
// this.generateData();
// }, 100);
}
ngOnDestroy() {
this.subscription.unsubscribe();
this.connection.stop();
}
private generateData() {
let end = this.counter+2;
for(let i = this.counter; i < end; i++) {
var d = { id: this.counter, name: "" + this.counter };
this.secretData.set(d.id, d);
this.counter++;
}
this.dataSubject.next(this.secretData);
}
}问题的第二部分是,正确的解决方法是什么(有多种变化检测机制)?我的实际代码是在一个服务中,而不是在一个组件中&我想正确的修复方法是在某个地方注入一个区域&使用zone.run,因为服务可能不应该触发gui检测更新。
样本角前沿项目:http://www.filedropper.com/angular-app
编辑以运行:
npm安装
吴服务
编辑:
如果使用setTimeout (例如2000 ms )运行创建,它将在其中。所以我想解释的是一些时间问题。
setTimeout(() =>
{
// Works everything will be inside zone
this.connect();
}, 0);
// callbacks in the connect will be outside
this.connect();连接是从上面重构出来的
private connect() {
let uri = 'http://localhost:8080/fake/signalr';
let c = $.hubConnection(uri, { useDefaultPath: false });
this.connection = c;
c.logging = true;
let hub = c.createHubProxy('myHub');
hub.on('tick', () => {
console.log(`tick: ${NgZone.isInAngularZone()}`);
this.generateData();
});
c.start().always(() =>
{
console.log(`Calling getData: ${NgZone.isInAngularZone()}`);
hub.invoke('getData')
.always(() => {
console.log(`getData: ${NgZone.isInAngularZone()}`);
this.generateData();
});
});
}发布于 2018-02-28 18:31:51
当异步操作在角区域内运行时
当您的角度组件使用计时器(setTimeout)调用函数时,NgZone会在角区域中捕获它以触发更改检测。同样,如果您在角声明内建立了一个WebSocket连接,那么它将在角区域中捕获。
何时和为什么SignalR是不同的
在组件方法中同步连接SignalR的原因并不使它在角区域内运行,原因是SignalR使用的是real,即非Zoned window.WebSocket或其他异步通信通道,而不是在NgZone中注册的信道。
绘制与AngularJS的平行图
如果您熟悉AngularJS,那么与您的示例相当的是,您的角度组件使用的是$timeout,而SignalR客户端本身使用的是本机setTimeout。
运行服务器时要小心,在角度区域内推送服务器。
虽然您可以在角区域内运行SignalR消息,但似乎运行角区域中来自服务器推送源(如WebSocket和SignalR)的每条异步消息很容易导致性能问题。
附加读数
如果您想了解更多关于Zone.js和NgZone的信息,以下是一些有价值的资源:
NgZonehttps://stackoverflow.com/questions/41848898
复制相似问题