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