Angular 事件订阅的潜在问题
Potential issue with subscription on event with Angular
在没有 Subscription 对象的情况下,在事件期间订阅服务(例如单击按钮)会带来问题吗?例如,这是我偶然发现的一个小片段:
usernames: string[];
...
public getFullName(userID: string) {
this.restApi.getFullName(userID).subscribe(response => {
this.usernames.push(response);
});
}
我想知道是否为每次调用该服务“添加”了订阅? (第一个调用添加一个订阅,推送一个项目,然后第二个调用添加另一个订阅到这个 Observable 并推送一个项目两次,依此类推)
更好的做法是在 OnInit() 方法中订阅每个服务,这样您只订阅一次而不会出现内存/性能问题?或者使用订阅对象来确保您的订阅在第二次调用时被“覆盖”?
您的订阅越少,您的应用就越有可能在没有任何内存问题的情况下运行。
上面的代码已经够危险了,因为您订阅了每个事件并且永远不会取消订阅。
换句话说,如果您需要在每次点击时都创建一个订阅,您可以支持它,但如果您只在初始化时创建一个订阅,则效率会更高。
我建议您阅读这篇文章:when-to-unsubscribe
还有这个:how-to-unsubscribe
#编辑
我真的很喜欢 @MoxxiManagarm 的另一个答案的代码,只留下我的两个词,因为我真的相信这篇文章很有帮助如果有人最终阅读了这个问题.
你的怀疑是对的。我为您的用例推荐 scan
运算符。
lastUserIdRequested: Subject<string> = new Subject();
usernames: string[];
ngOnInit() {
this.lastUserIdRequested.pipe(
concatMap(userId => this.restApi.getFullName(userId)),
scan((acc, fullname) => [...acc, fullname], []),
).subscribe(fullnames => this.usernames = fullnames);
}
public getFullName(userId: string) {
// this could be called directly from template without the getFullName method
this.lastUserIdRequested.next(userId);
}
每次 getFullName
都会添加一个新订阅,所以是的;表演将因此受到影响。您可以像 MoxxiManagarm 所说的那样使用 scanner
或者您可以使用 takeWhile
:
简化逻辑
public getFullName(userID: string) {
let isAlive = true;
this.restApi.getFullName(userID).pipe(
takeWhile(() => isAlive)
).subscribe(response => {
isAlive = false;
this.usernames.push(response);
});
}
takeWhile
运算符关闭订阅并在达到特定条件时将其删除。
在没有 Subscription 对象的情况下,在事件期间订阅服务(例如单击按钮)会带来问题吗?例如,这是我偶然发现的一个小片段:
usernames: string[];
...
public getFullName(userID: string) {
this.restApi.getFullName(userID).subscribe(response => {
this.usernames.push(response);
});
}
我想知道是否为每次调用该服务“添加”了订阅? (第一个调用添加一个订阅,推送一个项目,然后第二个调用添加另一个订阅到这个 Observable 并推送一个项目两次,依此类推)
更好的做法是在 OnInit() 方法中订阅每个服务,这样您只订阅一次而不会出现内存/性能问题?或者使用订阅对象来确保您的订阅在第二次调用时被“覆盖”?
您的订阅越少,您的应用就越有可能在没有任何内存问题的情况下运行。
上面的代码已经够危险了,因为您订阅了每个事件并且永远不会取消订阅。
换句话说,如果您需要在每次点击时都创建一个订阅,您可以支持它,但如果您只在初始化时创建一个订阅,则效率会更高。
我建议您阅读这篇文章:when-to-unsubscribe 还有这个:how-to-unsubscribe
#编辑
我真的很喜欢 @MoxxiManagarm 的另一个答案的代码,只留下我的两个词,因为我真的相信这篇文章很有帮助如果有人最终阅读了这个问题.
你的怀疑是对的。我为您的用例推荐 scan
运算符。
lastUserIdRequested: Subject<string> = new Subject();
usernames: string[];
ngOnInit() {
this.lastUserIdRequested.pipe(
concatMap(userId => this.restApi.getFullName(userId)),
scan((acc, fullname) => [...acc, fullname], []),
).subscribe(fullnames => this.usernames = fullnames);
}
public getFullName(userId: string) {
// this could be called directly from template without the getFullName method
this.lastUserIdRequested.next(userId);
}
每次 getFullName
都会添加一个新订阅,所以是的;表演将因此受到影响。您可以像 MoxxiManagarm 所说的那样使用 scanner
或者您可以使用 takeWhile
:
public getFullName(userID: string) {
let isAlive = true;
this.restApi.getFullName(userID).pipe(
takeWhile(() => isAlive)
).subscribe(response => {
isAlive = false;
this.usernames.push(response);
});
}
takeWhile
运算符关闭订阅并在达到特定条件时将其删除。