Angular Rxjs 多个并行 HTTP 请求/调用阻塞导航 - 优先取消队列并发

Angular Rxjs Multiple Parallel HTTP Requests / Calls blocking navigation - Priority Cancel Queue Concurrent

我知道有类似的线程,但没有一个可以为我的问题提供合适的解决方案。

Pre: 我同时在服务器端和客户端导航。这意味着在前端使用 routerLink 进行的每次导航和调用的任何路由都伴随着对服务器的 HTTP 请求调用。

情况:我正在打开一个对话框以显示用于创建 position 的表单。为此 position 我需要显示我从 API 加载的 elements 列表。对于每个 element,我需要加载一个额外的 thumbnail。所以我需要一个 API 调用来获取 86 个 elements,然后需要 86 个请求来获取 thumbnail。我将这些元素保存在服务中以防止再次加载它们。因此,我在加载它们之前检查是否已经有 elements。 API 调用在我打开对话框时启动。

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;
                        }
                    );
                });
            }
        );
    }
}

缩略图请求方法:

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);
        })
    );
}

问题:如果用户决定取消表单并想要导航 forward/backward - 他不能,因为 navigation request 在队列的末尾。

是否有任何方法可以将 thumbnail 调用的优先级设置为较低的调用以在较小的负载上处理?

提前致谢。

问题是浏览器对同一端点的并行请求有限制。 api 是否与前端同源?如果不是,则限制可能会更低。

我的看法:

  1. 为缩略图使用 url。我假设您将它们显示在某些 img 标签中。为什么不设置 href 并让浏览器处理图像的加载。继续这个想法,您可以使用 "inview" 指令来延迟图像的加载,直到它们实际可见(这也取决于业务和要求)。

  2. 将并行请求限制为 getThumbnail。您可以这样做(使用 mergeMap 的 concurrent 参数):

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();