簡體   English   中英

在 RxJS 中,是否應該在不發出任何項目的可觀察對象中調用 complete?

[英]In RxJS, should complete be called in an observable that emits no items?

在我的上一篇文章中,我嘗試使用 RxJS 緩沖待處理的 http 請求。 我認為bufferCount是我需要的,但我發現我的項目低於緩沖區大小,它只會等待,這不是我想要的。

我現在有一個新方案,使用take 它似乎在做我所追求的,除非我得到的可觀察對象沒有項目(左),否則永遠不會調用完整的。

例如,我有類似以下內容..

      const pendingRequests = this.store$.select(mySelects.getPendingRequests).pipe(
      // FlatMap turns the observable of a single Requests[] to observable of Requests
      flatMap(x => x),

      // Only get requests unprocessed
      filter(x => x.processedState === ProcessedState.unprocessed),

      // Batches of batchSize in each emit
      take(3),
    );
    
    let requestsSent = false;
    pendingRequests.subscribe(nextRequest => {           
      requestsSent = true;
      this.sendRequest(nextEvent);           
     },
      error => {            
        this.logger.error(`${this.moduleName}.sendRequest:  Error ${error}`);
      },
      () => {         
        // ****  This is not called if pendingRequests is empty ****
        if (requestsSent ) {              
          this.store$.dispatch(myActions.continuePolling());              
        } else {
          this.store$.dispatch(myActions.stopPolling());              
        }
      }
    );

因此take(3)將獲取接下來的 3 個待處理請求並將它們發送 () 我還調度一個操作以將已處理的 state 設置為 not ProcessedState.pending 所以我們不會在下一次輪詢中得到它們

這一切都很好,但是當pendingRequests最終什么都不返回(為空)時, completed的塊用 **** 標記。 不叫。 我原以為這會立即被調用。

我不確定這是否重要,因為我沒有發送操作以繼續輪詢,因此輪詢確實停止了。

但我最擔心的是,如果pendingRequests沒有完成,我是否需要取消訂閱以防止任何泄漏? 我假設如果調用complete ,我不需要取消訂閱?

更新

為了讓pendingReguests總是完成,我采取了一種稍微不同的方法。 我沒有使用rx運算符來“過濾”,而是每次都獲取整個列表,然后對其take(1) 我總是會得到列表,即使它是空的,所以pendingReguests每次都會完成。

IE

const pendingRequests = this.store$.select(mySelects.getPendingRequests).pipe(take(1))

然后我可以在 observable 中過濾和批處理..

 pendingRequests.subscribe(nextRequest => {
      let requestToSend = nextRequest.filter(x => x.processedState === ProcessedState.unprocessed);
      const totalPendingCount = requestToSend.length;
      requestToSend = requestToSend slice(0, this.batchSize);          
      for (const nextRequest of requestToSend) {                  
          this.sendRequest(nextRequest);            
      }

      if (totalPendingCount > this.batchSize) {
        this.store$.dispatch(myActions.continuePolling());            
      }

到目前為止,在我的測試中,我現在總是可以complete開火。

此外,通過 2 個操作(一個 startPolling 和一個 continuePolling),我可以將延遲放在 continuePolling 中,所以當我們第一次開始輪詢時(例如,應用程序在超出網絡范圍后剛剛恢復在線),我們立即提交,只有在我們有超過批量大小時才會延遲

也許這不是 100% 的“rxy”方式,但到目前為止似乎有效。 這里有什么問題嗎?

之后我會用toArray和一些緩沖邏輯代替take

這就是您的代碼的樣子。 我添加了delay邏輯,我認為這是您之前的帖子所建議的,並提供了評論來描述添加的每一行

// implementation of the chunk function used below
// https://www.w3resource.com/javascript-exercises/fundamental/javascript-fundamental-exercise-265.php
   const chunk = (arr, size) =>
      Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
        arr.slice(i * size, i * size + size)
      );

  const pendingRequests = this.store$.select(mySelects.getPendingRequests).pipe(
  // FlatMap turns the observable of a single Requests[] to observable of Requests
  flatMap(x => x),

  // Only get requests unprocessed
  filter(x => x.processedState === ProcessedState.unprocessed),

  // Read all the requests and store them in an array
  toArray(),
  // Split the array in chunks of the specified size, in this case 3
  map(arr => chunk(arr, 3)), // the implementation of chunk is provided above
  // Create a stream of chunks
  concatMap((chunks) => from(chunks)),
  // make sure each chunk is emitted after a certain delay, e.g. 2 sec
  concatMap((chunk) => of(chunk).pipe(delay(2000))),
  // mergeMap to turn an array into a stream
  mergeMap((val) => val)
);

let requestsSent = false;
pendingRequests.subscribe(nextRequest => {           
  requestsSent = true;
  this.sendRequest(nextEvent);           
 },
  error => {            
    this.logger.error(`${this.moduleName}.sendRequest:  Error ${error}`);
  },
  () => {         
    // ****  THIS NOW SHOULD BE CALLED ****
    if (requestsSent ) {              
      this.store$.dispatch(myActions.continuePolling());              
    } else {
      this.store$.dispatch(myActions.stopPolling());              
    }
  }
);

我懷疑pendingRequests是否會自行完成。 Store至少在 ngrx 中是一個BehaviorSubject 因此,每當您執行store.select()store.pipe(select())時,您只是將另一個訂閱者添加到由BehaviorSubject維護的訂閱者的內部列表中。

BehaviorSubject 擴展了Subject ,以下是訂閱Subject時發生的情況:

this.observers.push(subscriber);

在您的情況下,您正在使用take(3) 在 3 個值之后, take將發出一個完成通知,因此應該調用您的complete回調。 並且因為整個鏈實際上是一個BehaviorSubject的訂閱者,它會在complete通知時將自己從訂閱者列表中刪除。

我假設如果調用完整,我不需要取消訂閱

以下是訂閱者(例如TakeSubscriber完成時發生的情況:

  protected _complete(): void {
    this.destination.complete();
    this.unsubscribe();
  }

因此,如果已經發生complete / error通知,則無需取消訂閱。

暫無
暫無

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

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