簡體   English   中英

如何手動完成angular http observable

[英]How to manually complete the angular http observable

我正在開發多個並行文件上傳功能,能夠刪除/取消正在進行的 http 調用。 一旦所有呼叫完成/取消,我就會通知消費者。

為此,我使用forkJoin組合各個 http observables。 但是如果用戶點擊取消按鈕,我不應該等待實際 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;
    }));
}

使用takeUntil和一個 Subject 作為通知程序來完成 Observables。 您可以將文件 id 傳遞給 Subject 並在takeUntil使用filter來僅取消具有給定 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

將訂閱分配給變量並使用按鈕取消它:

$http: Subscription;
this.$http = this.http.post(this.uploadUrl, formData, {
      reportProgress: false
      // observe: 'events',
});

在取消功能中:

cancelUpload(file: any) {
  file.uploadStatus = "cancelled"; 
  this.$http.unsubscribe();
}

除了takeUntil我們還可以使用mergerace運算符來處理這種情況。 然而,它並沒有改變底層邏輯。

第 1 步:為個人上傳創建Subject

file.cancelUpload$ = new Subject();

第 2 步:將此主題與實際的 http 調用合並

如果任何 observable 發出錯誤,merge 將完成流。 即,當我們從cancelUpload$主題發出錯誤時,http 請求將自動取消(查看網絡選項卡)。

return merge(file.cancelUpload$, $http.pipe(...

第 3 步:實際取消代碼

cancelUpload(file: any) {
  file.uploadStatus = "cancelled";
  file.cancelUpload$.error(file.uploadStatus);// implicitly subject gets completed
}

第 4 步:在上傳錯誤/成功的情況下完成cancelUpload$主題

它將確保merge操作將完成,因為兩個流現在都已完成。 因此forkJoin將收到響應。

參考https://stackblitz.com/edit/angular-zteeql?file=src%2Fapp%2Fhttp-example.ts

  uploadFiles() {
    let errorCount = 0,cancelledCount = 0, successCount = 0;
    return forkJoin(
      this.dummyFiles
        .map(file =>
          this.uploadFile(file).pipe(
            catchError(() => of("Error re-emitted as success")) // value doesn't matter
          )
        )
    ).pipe(
      map(() => { // map would receive array of files in the order it was subscribed
        this.dummyFiles.forEach(file => {
          switch (file.uploadStatus) {
            case "success": successCount++; break;
            case "cancelled": cancelledCount++; break;
            case "error": errorCount++; break;
          }
        });
        return { errorCount, successCount, cancelledCount };
      })
    );
  }

  uploadFile(file: any) {
    const formData = new FormData();
    const binaryContent = new Blob([Array(1000).join("some random text")], {
      type: "text/plain"
    }); // dummy data to upload
    formData.append("file", binaryContent);
    const $http = this.http.post(this.uploadUrl, formData, {
      reportProgress: false
      // observe: 'events',
      // withCredentials: true
    });
    file.cancelUpload$ = new Subject();
    file.uploadStatus = "inProgress";
    return merge(
      file.cancelUpload$,
      $http.pipe(
        tap(data => {
          file.uploadStatus = "uploaded";
          file.cancelUpload$.complete();
        }),
        catchError(event => {
          file.uploadStatus = "error";
          file.cancelUpload$.complete();
          return throwError("error");
        })
      )
    );
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM