Reputation: 1851
Can subscribing to a service during an event (e.g with clicking a button) bring issue when done without a Subscription object ? For instance, here is a small snippet I stumbled upon:
usernames: string[];
...
public getFullName(userID: string) {
this.restApi.getFullName(userID).subscribe(response => {
this.usernames.push(response);
});
}
I was wondering if a subscription was "added" for each call to the service ? (the first call adds a subscription, which pushes one item, then a second adds another subscription to this Observable and pushes an item twice, and so on and so on)
It is a better practice to subscribe to every services in an OnInit() method, so that you subscribe only once without memory / performance issues ? Or use a Subscription object to make sure that your subscription is "overrid" when called a second time ?
Upvotes: 1
Views: 205
Reputation: 2926
The less subscriptions you have, the better chances that your app will work without any memory issue.
The code above is dangerous enough because you subscribe for every event and you never unsubscribe.
In other words, If you need to create a subscription on every click you can support it but If you could just create one subscription on initialized it would more efficient.
I would suggest you to read this article: when-to-unsubscribe and this one: how-to-unsubscribe
#Edit
I really like the code of the other answer here by @MoxxiManagarm, just leaving my two words because I really believe that this articles are helpful If someone ends up reading this question.
Upvotes: 1
Reputation: 3433
Everytime getFullName
a new subscription is added, so yes; Performances will suffer for this. You could use a scanner
as MoxxiManagarm said or you can simplify the logic using takeWhile
:
public getFullName(userID: string) {
let isAlive = true;
this.restApi.getFullName(userID).pipe(
takeWhile(() => isAlive)
).subscribe(response => {
isAlive = false;
this.usernames.push(response);
});
}
The takeWhile
operator closes the subscripion and removes it when a certain condition is reached.
Upvotes: 1
Reputation: 9134
Your doubts are true. I recommend the scan
operator for your usecase.
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);
}
Upvotes: 1