当我使用Observable.Interval
对UI执行http刷新时,如果间隔过快,它会锁定UI上的按钮。按钮没有记录点击,似乎是时间问题。如果我增加了时间,因此错过了get调用,按钮就会工作,但数据在更新时会延迟。
间隔
this.dataSub = Observable.interval(1000).subscribe(x => {
this.getData();
})
getData
getData(): void {
this.dataService.getData()
.subscribe(
data => this.data = data,
error => console.log("Error HTTP Get Service" + this.data),
() => {});
}
有没有一个最佳实践,或者我错过了什么,我应该做刷新UI,但不锁定按钮
理论
一般来说,您应该尽可能避免显式订阅可观察性。相反,使用所有可用的运算符(是的,要找出正确的运算符可能非常困难)将所有源/输入可观察器组合为一个或多个可观察性,您可以在具有async
管道的视图中使用它们。
不要忘记JS是单线程的(除了worker)。你的UI和大多数Angular代码必须共享一个线程,所以只要运行JS就会锁定你的UI。
这有三个主要好处:
- 几乎不可能导致内存泄漏。如果你不记得总是在
ngOnDestroy()
挂钩中取消订阅,或者当你不再关心它时,你就有可能在手动订阅时造成内存泄漏。而async
管道在其使用的组件/元素被销毁时将正确取消订阅,您不必担心 - 少做工作。使用
switchMap()
、switchLatest()
等运算符,您可以取消和清除被取代的HTTP调用和其他昂贵的操作,如果不再需要,甚至可以在它们开始之前停止它们。不要做得太多。这通常也意味着更改检测不必运行那么多,这意味着性能更好 - 清洁器代码。更少的成员变量,更像函数的代码。是的,当你学习Rx时,可能会有点难以理解,但它会变得更容易
在实践中
考虑到所有这些,您如何将其应用于您的代码?
有一件事你可能没有意识到(很多人没有意识到),如果你的DataService.getData()
方法是这样的:
getData(): Observable<MyData[]> {
return this.http.get('http://some.url/data').map(res => res.json());
}
然后,每次订阅Http
服务创建的observable时,都会发出一个新的请求。这是您想要的,但您不想要的是在发出新请求后立即处理任何以前请求的结果。
因此,你可以在你的控制器中使用这样的东西,用最近请求的最新数据组成一个可观察的:
ngOnInit() {
// (I follow a convention where observable properties end in $)
this.data$ = Observable.interval(1000).flatMapLatest(() => {
return this.dataService.getData();
});
}
没有订阅,只有一个创建的可观察对象。然后,在您的视图中,只需使用带有data$
属性的异步管道,您就可以获得金牌。
例如:
<ul *ngFor="let d of (data$ | async); trackBy: d?.id">
<li>{{d.name}}</li>
</ul>