我有这个在滚动表时被多次调用的方法:
setViewportRange(firstRow: number, lastRow: number): void {
this.getViewport(firstRow, lastRow).subscribe(message => {
console.log(message);
});
}
我没有控制 setViewportRange 方法的调用,但我需要去反弹它。所以我用帮助 lodash 的去抖动函数创建了这个 debouncedGetViewport 方法:
setViewportRange(firstRow: number, lastRow: number): void {
this.debouncedGetViewport(firstRow, lastRow);
}
debouncedGetViewport = debounce((firstRow, lastRow) => {
return this.getViewport(firstRow, lastRow).subscribe(message => {
console.log(message);
});
}, 1000);
它有效! 但是一位同事问我为什么不使用RxJs去抖动。所以我尝试用 RxJs 实现它,但我无法让它工作。无论传递哪个值,去抖时间都不起作用! 你能帮我理解为什么这不起作用吗?我想我误解了什么。
setViewportRange(firstRow: number, lastRow: number): void {
this.debouncedGetViewport(firstRow, lastRow);
}
debouncedGetViewport = (firstRow, lastRow) => {
return this.getViewport(firstRow, lastRow)
.pipe(debounceTime(1000))
.subscribe(message => {
console.log(message);
});
};
谢谢!
首先不要忘记取消订阅!
首先,从内存泄漏的角度或多次订阅时的奇怪行为来确保调用setViewportRange
时this.getViewport
。你不知道this.getViewport
背后发生了什么.可能会多次调用getViewport.subscribe的回调。最好始终取消订阅。
如何取消订阅?有几种方法可以取消订阅可观察量,但在您的情况下,您只需使用take
运算符即可。
debouncedGetViewport = debounce((firstRow, lastRow) => {
return this.getViewport(firstRow, lastRow).pipe(take(1)).subscribe(message => {
console.log(message);
});
}, 1000);
以下是您应该取消订阅的一些资源:
- https://netbasal.com/when-to-unsubscribe-in-angular-d61c6b21bad3
- Angular/RxJS 我什么时候应该取消订阅"订阅">
你没有准确地描述什么不起作用!
我根据您的示例问题创建了一个游乐场,我想我知道您的意思:"您能否帮助我理解为什么这不起作用"。
我想控制台.log被调用,但debounceTime
没有效果,对吧?请确保下次在问题描述中准确解释哪些内容不起作用。您可能会被扣负分。
为什么你的去抖动时间不起作用?
我认为这是Nuno Sousa的一个很好的堆栈溢出解释,为什么你的debounceTime
示例不起作用!
考虑你的逻辑。您将为每个更改创建一个最终的观察程序。它不会去抖动,因为观察者已经完成,去抖动是为了防止发射一个,以防另一个来临。因此,它至少需要两个发射才能合理(或更多(,如果在回调中创建观察者,则不会发生这种情况。
似乎您正在用this.getViewport
创建一个最终(已完成(的可观察量,该可观察量在发出第一个值后立即完成,这就是debounceTime
在这里不起作用的原因。
提示:如果可观察量已经完成,则take(1)
不起作用,但最佳做法是始终取消订阅订阅。
您需要不同的解决方案!
unsubscribe$ = new Subject();
rows$: Subject<{firstRow: number, lastRow: number}> = new Subject();
ngOnInit() {
this.rows$.pipe(
debounceTime(500),
switchMap(({firstRow, lastRow}) => this.getViewport(firstRow, lastRow)),
takeUntil(unsubscribe$)
).subscribe(resultOfGetViewport => {
console.log(resultOfGetViewport);
});
}
setViewportRange(firstRow: number, lastRow: number) {
this.rows$.next({firstRow, lastRow});
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
我已经为前面的代码创建了一个堆栈闪电战示例!
我们不同的解决方案中发生了什么?
在我们的新解决方案中,我们不使用最终的可观察量,因为我们使用Subject (rows$)
并且主题无法像getViewport
那样完成自身。我们必须明确地自己做。我们可以在takeTill 运算符中看到这一点。只有当组件被销毁时,所以当调用ngOnDestroy
时,我们才会告诉我们的 rows$ observable 完成自身。最后但并非最不重要的一点是,我们从getViewport
switchMap
中获得价值。就是这样。
您可能想知道debounceTime
和switchMap
的顺序在这里是否有区别。这要看情况!如果this.getViewport
是一项昂贵的操作,那么将其放在debounceTime
之后,如果它非常便宜,那么订单无关紧要。