[英]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.