首页 > 解决方案 > 如何手动完成 angular http observable

问题描述

我正在开发多个并行文件上传功能,能够删除/取消正在进行的 http 调用。一旦所有呼叫完成/取消,我就会通知消费者。

为此,我使用forkJoin. 但是如果用户点击取消按钮,我不应该等待实际 http 响应的完成。

takeUntill 不会优雅地处理它,因为它只会在从底层源 http 流接收到下一个值后才会采取行动。

this.uploadFiles().subscribe(data => {
  console.warn("Upload completed now!!!!!", data);
});

uploadFiles() {
  return forkJoin(
    this.files.map(file => // returns array of observable
        this.uploadFile(file).pipe( catchError(() => of("Error re-emitted as success to prevent early exit"))))
  ).pipe(map(() => {
       // logic for some user friendly statistic
      return data;
    }));
}

标签: angularrxjshttpclientangular8

解决方案


与 Subject 一起使用takeUntil作为通知者来完成 Observables。您可以将文件 id 传递给 Subject 并使用filterintakeUntil仅取消具有给定 id 的文件的文件上传。

用于defaultIfEmpty提供指示已取消请求的值。这也可以防止在forkJoin内部空请求完成时外部立即完成。

private cancelUpload$ = new Subject<number>();

uploadFiles() {
  let errorCount = 0, cancelledCount = 0, successCount = 0;
  return forkJoin(this.dummyFiles.map(file =>
    this.uploadFile(file).pipe(
      // react to CANCEL event
      map(response => response == 'CANCEL' ? ++cancelledCount : ++successCount),
      catchError(() => of(++errorCount))
    )
  )).pipe(map(() => ({ errorCount, successCount, cancelledCount })));
}

uploadFile(file: any) {
  http$.pipe(
    ...
    takeUntil(this.cancelUpload$.pipe(filter(id => id == file.id))), // cancel
    defaultIfEmpty('CANCEL'), // provide value when cancelled
  )
}

cancelUpload(file: any) {
  file.uploadStatus = "cancelled";
  this.cancelUpload$.next(file.id) // cancel action
}

https://stackblitz.com/edit/angular-zteeql-e1zacp


推荐阅读