关于 rxjs debounceTime 的困惑



我有这个在滚动表时被多次调用的方法:

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

谢谢!

首先不要忘记取消订阅!

首先,从内存泄漏的角度或多次订阅时的奇怪行为来确保调用setViewportRangethis.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 完成自身。最后但并非最不重要的一点是,我们从getViewportswitchMap中获得价值。就是这样。

您可能想知道debounceTimeswitchMap的顺序在这里是否有区别。这要看情况!如果this.getViewport是一项昂贵的操作,那么将其放在debounceTime之后,如果它非常便宜,那么订单无关紧要。

最新更新