簡體   English   中英

如何在沒有等待的情況下使用可觀察的

[英]How to use observable without await

我有以下代碼,這似乎有效,但我很確定有一種更簡潔的方法可以使用鏈接運算符來實現它,事實是我在上面掙扎了 2 個小時,但無法使其正常工作用另一種方式。

也許你可以幫助我?

  public synchronizeWithRemote$(state: Partial<StorageCustomerCase>, pdfDocument?: InkPDFDocument): Observable<ISynchronizationProgress> {
return new Observable((subscriber) => {
  // PDF as changed, we update the hash
  if (pdfDocument) {
    this.pdfInvalidationHash = nanoid();
    // Start synchronization task
    pdfDocument
      .serialize()
      .then((serializedDoc) => {
        const task = this.storageRef.put(serializedDoc, { contentType: "application/pdf" });

        // Listen for changes
        task.on("state_changed", ({ bytesTransferred, totalBytes }) => {
          subscriber.next({ bytesTransferred, totalBytes, percent: Math.round((bytesTransferred * 100) / totalBytes) });
        });

        return task; // Await the load to finish before uploading to firestore the metadatas
      })
      .then(() =>
        this.documentRef.update({ ...omit(state, "id"), pdf_invalidation_hash: this.pdfInvalidationHash } as StorageCustomerCase),
      )
      .then(() => subscriber.complete());
  } else {
    subscriber.next({ bytesTransferred: 0, percent: 100, totalBytes: 0 });
    // TODO: Update this function to use only observable by chaining
    // Just update doc
    this.documentRef
      .update({ ...omit(state, "id"), pdf_invalidation_hash: this.pdfInvalidationHash } as StorageCustomerCase)
      .then(() => {
        // Notify firebase of changes, once PDF has been successfully uploaded.
        subscriber.complete();
      });
  }
});

}

如果有PDF文檔,它應該發送一個進度指示器,並在上傳后與firestore同步,否則,它僅在與firestore同步后完成。

問候, 安德烈亞斯

這應該與使用 Promise 的語義大致相同,僅使用 Observables。 出於顯而易見的原因,我實際上無法為您進行測試,因此請將其用作答案的草圖而不是整個答案。

我也不確定fromEventPattern適用於您的情況。 看起來應該如此。

public synchronizeWithRemote$(state: Partial<StorageCustomerCase>, pdfDocument?: InkPDFDocument): Observable<ISynchronizationProgress> {
  
  const finish$ = defer(() => this.documentRef.update({
    ...omit(state, "id"), 
    pdf_invalidation_hash: this.pdfInvalidationHash 
  } as StorageCustomerCase));

  if(doc == null){
    // No updates, finish right away
    return finish$.pipe(
      startWith({ bytesTransferred: 0, percent: 100, totalBytes: 0 })
    );
  }
  
  // Stream of state Changes
  const update$ = defer(() => doc.serialize()).pipe(
    tap(_ => this.pdfInvalidationHash = nanoid()),
    map(serializedDoc => 
      this.storageRef.put(serializedDoc, { 
        contentType: "application/pdf" 
      })
    ),
    switchMap(task =>
      fromEventPattern(
        handler => task.on("state_changed", handler)
      ).pipe(
        map(({ bytesTransferred, totalBytes }) => ({ 
          bytesTransferred, 
          totalBytes, 
          percent: Math.round((bytesTransferred * 100) / totalBytes) 
        }))
      )
    )
  );
  
  // Wait for update$ to complete before subscribing to finish$
  return concat(update$, finish$);
}

將承諾轉換為可觀察的

許多 RxJS 操作符,如果給定一個 promise,就會隱式地將它們轉換為 obervable。 以下是一些:

  1. from(promise)
  2. defer(() => promise)
  3. mergeMap/switchMap/concatMap(val => promise)

我不是#1 的忠實粉絲。 雖然#2 和#3 保持承諾的行為就像一個可觀察的(在您訂閱之前什么都不會發生),#1 將立即啟動承諾。 任何事情都有時間和地點,但是使用 #1 產生的錯誤在這里很常見,所以我認為值得一提。

一個很好的例子 如果我在這里使用 #1 而不是 #2 作為完成 $,那么pdf_invalidation_hash將具有錯誤的值。 因為它的值取決於訂閱完成 $ 的時間(在update$運行后,應該更新this.pdfInvalidationHash )。

暫無
暫無

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

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