我在角度组件中有以下代码来捕获 keyup
事件并在发生这种情况时做出响应。用户可以离开页面,返回并执行数百次相同的操作。
fromEvent(this.input?.nativeElement, 'keyup')
.pipe(
pluck<unknown, string>('target', 'value'),
filter((searchTerm: string) => (searchTerm?.length > 2 || searchTerm?.length == 0)),
throttleTime(200),
debounceTime(300),
distinctUntilChanged()
)
.subscribe(search => {
this.setPageIndex();
this.TriggerLoadUsers(search, 'asc', 0, 10);
});
这是另一种模式,其中 Subscription
的显式分配已完成,然后在 angular 生命周期方法的 ngOnDestroy
中取消订阅。
public keyupEventsSub$!: Subscription;
this.keyupEventsSub$ = fromEvent(this.input?.nativeElement, 'keyup')
.pipe(
pluck<unknown, string>('target', 'value'),
filter((searchTerm: string) => (searchTerm?.length > 2 || searchTerm?.length == 0)),
throttleTime(200),
debounceTime(300),
distinctUntilChanged()
)
.subscribe(search => {
this.setPageIndex();
this.TriggerLoadUsers(search, 'asc', 0, 10);
});
this.keyupEventsSub$.unsubscribe();
Subscription
、subscribed
和 unsubscribed
的第二种模式是否有优势?Observable
订阅使用相同的模式有什么副作用吗?答案 0 :(得分:1)
1.) 是的,应该取消订阅所有订阅以防止内存泄漏。您不必取消订阅 Http 调用或路由器事件,因为它们是一个并且已经完成并且 Angular 会为我们处理它,但我个人仍然取消订阅所有订阅。
2.) 对任何可观察订阅使用相同的模式没有副作用。模式很多,我会在最后展示。
3.) 有一个更好的模式,我将从最不喜欢到最喜欢。
直接订阅分配。这样做的缺点是每个可观察流都有许多订阅变量,因此可能会失控。
// Direct subscription variable (What you have shown)
// don't put a dollar at the end of subscription variable because
// it is a subscription and not an observable
public subscription!: Subscription;
....
this.subscription = this.observable$.subscribe(...);
...
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
订阅数组: 将每个订阅添加到数组中。
public subscriptions!: Subscription[];
...
this.subscriptions.push(this.observable$.subscribe(...));
...
ngOnDestroy(): void {
this.subscriptions.forEach(subscription => subscription.unsubscribe());
}
异步管道: 我的最爱之一,但只能在 HTML 中呈现数据时使用,不能用于事件侦听器(本质上意味着每次 observable 发出时都做出反应)。 当视图呈现时,observable 将自动被订阅,一旦视图被销毁,订阅将被取消订阅。
count$ = this.otherObservable$.pipe(map(data => data.count));
...
<h1>{{ count$ | async }}</h1>
破坏主题: 另一个我最喜欢的,这个适用于 TypeScript 类中的订阅(用于事件侦听器)。这种方法的美妙之处在于不会创建太多变量,而且您不必处理数组。
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
....
private destructionSubject$ = new Subject<void>();
...
observable$.pipe(
takeUntil(this.destructionSubject$),
).subscribe(...);
observable2$.pipe(
takeUntil(this.destructionSubject$),
).subscribe(...);
...
ngOnDestroy(): void {
this.destructionSubject$.next();
this.destructionSubject$.complete();
}
如果您只关心第一次排放而不是后续排放,还有另一种方式:
这可用于事件侦听器(每次此 observable 发出时都做出反应)。这将进行第一次发射并自动取消订阅(订阅已失效)。
import { take } from 'rxjs/operators';
....
observable$.pipe(take(1)).subscribe(...);
我希望我回答了您的所有问题,并为您提供了退订的好方法。
答案 1 :(得分:1)
只有可能永远不会Observables
或error
的complete
需要取消订阅。如果您不确定,最好取消订阅。
from(promise)
保证完成或出错。
from(['a','r','r','a','y'])
保证完成。
of(...)
保证完成。
EMPTY
保证完成。
NEVER
永远不会完成或失败。
fromEvent(...)
可能永远不会完成或失败。
http.get(...)
一个写得很好的 http 客户端应该总是完成或最终失败,但有一些(出于各种技术原因)不会。如果您不确定,请退订。
总的来说,隐式优于显式。有多种运营商会在满足特定条件时为您退订。
take
,
takeWhile
和
takeUntil
是其中最受欢迎的 3 个。与其在我们的代码中的某处粘贴 stream.unsubscribe()
相比,他们更喜欢它们。
这样做可以将所有关于可观察对象的逻辑集中在一个地方。随着您使用的 observable 数量的增加,维护/扩展变得更加容易。