i know there are similiar threads but there isnt one that provided a fitting solution for my problem.
Pre: I am navigating on the server side and on the client side at the same time. That means every navigation on the frontend with routerLink and any route which is called is accompanied by a HTTP request call to the server.
Situation: I am opening a dialog to show a form to create a position
. For this position
I need to show a list of elements
which I am loading from the API. For each element
I need to load an additional thumbnail
. So I need one API call to get the 86 elements
and then 86 requests to get the thumbnail
s. I am saving this elements within a service to prevent loading them again. Therefore I am checking if there are already elements
before going to load them. The API calls are started, when I am opening the dialog.
getElementsWithThumbnails() {
if (this.elementsSource.value.length === 0) {
this.apiService.getElements().subscribe(
(next) => {
this.elementsSource.next(next);
this.elementsSource.value.forEach((epl, index) => {
const format = 'JPG';
this.apiService.getThumbnail(epl.id, format, '400', '400', 'true').subscribe(
(blob) => {
epl.thumbnail = blob;
}
);
});
}
);
}
}
ThumbnailRequestMethod:
getThumbnail(
elementId: string, format: string, width: string,
height: string, sameratio: string
): Observable<SafeUrl> {
return this.httpClient.get(
this.apiUrl +
`/elements/${elementId}/thumbnail?format=${format}&width=${width}&height=${height}&sameratio=${sameratio}`
, {
responseType: 'blob'
}).pipe(
map(res => {
return this.blobToSanitizedUrl(res);
})
);
}
Problem: If the user decides to cancel the form and wants to navigate forward/backward - he cant, because the navigation request
is on the end of the queue.
Is there any method which sets priority of the thumbnail
calls on a lower one to be handle on a lesser load?
Thanks in advance.
The problem is that the browser has a limit to parallel requests to the same endpoint. Is the api on the same origin as the frontend? If it's not the limit is probably lower.
The way I see it:
Use urls for the thumbnails. I assume you display them in some img
tags. Why not set the href
and let the browser handle loading of the images. Going forward on this idea, you could use an "inview" directive to defer the loading of the images until they are actually in view (this also depends on the business and requirements).
Limit the parallel requests to getThumbnail
. You can do it like this (using the concurrent
parameter for mergeMap):
const format = 'JPG';
this.apiService.getElements()
.pipe(
switchMap(items => {
this.elementsSource.next(items);
return from(items);
}),
mergeMap(item => {
return this.apiService
.getThumbnail(item.id, format, '400', '400', 'true')
.pipe(
tap(blob => item.thumbnail = blob)
)
}, 2) // max 2 requests in parallel
)
.subscribe();