Reputation: 133
I am new to angular , started learning this past weeks. I have this list of notes which contain the noteId and userId , using the UserId I need to call another service , which returns me the username .
ngOnInit() {
this.items.forEach(element => {
this.userService.loadByUserId(element.UserId)
.subscribe(res => element.Name = res.Name) })
}
The loadByUserId contains the code to call the User API.
I am looking for ways to reduce the load on UserAPI , as the this.items can be very huge in numbers.
Does angular provide a way so that I can store the previous requests response , and check the object before firing a second request. The endgame is not on overload the server with high no of requests for userId
What I tried to implement is basically create a list which stores the response , in a if else , before sending the request , I am checking if the list contains the userid , name combination , if not return from the list or else send request to server.
The problem with the above approach is that the loop just executes or iterates itself over it 100(assuming?) records and does not wait for the loadByUserId method to return response.
Please suggest what is the best way to implement this in angular using await/observables approach
I tried to implement this , but it doesnt send the user API req.
loadByUserGuid(userId: string): Observable<any> {
return this._api.get('User/' + userId).map(res => {
return res;
});
}
Observable.from(this.items).concatMap(element => this.userService.loadByUserGuid(element.UserId).do(res => element.Name = res.Name)).subscribe(() => { });
The idea is to cache/store the response of User API , to avoid sending multiple requests
Upvotes: 0
Views: 62
Reputation: 133
I eventually solved this bys using a Map , which is like a C# Dictionary. The Map returns a Observable Object which can be subscribed to , thus causing the loop execution to wait for the response and then iterate to next element.
cache = new Map<string, Observable<any>>();
loadByUserId(userId: string) {
if (userId != null) {
if (!this.cache.has(userId)) {
this.cache.set(userId, this._api.get('User/' + userId).pipe().shareReplay(1));
}
return this.cache.get(userId);
}
return Observable.empty();
}
Upvotes: 0
Reputation: 8295
The obvious answer would be to change the api to expose a loadByIDs
method that can load multiple users.
If this is not possible, you can mergeMap the requests with a concurrency limit (set at 10 in this example):
Observable.from(items)
.mergeMap(element =>
this.userService
.loadByUserId(element.UserId)
.do(res => element.Name = res.Name),
10) //at most 10 requests in the same time
.subscribe(() => {}); //start doing the jobs
If you want to do it sequentially, you can use concatMap
which waits for the previous request to finish before starting a new one:
Observable.from(items)
.concatMap(element =>
this.userService
.loadByUserId(element.UserId)
.do(res => element.Name = res.Name))
.subscribe(() => {}); //start
Upvotes: 1