我有一个RXJS主题,当我向它发出(下一个)时,会在5秒后发出HTTP呼叫和超时。我已经关闭后端,以便它总是超时。超时导致调用subscribes error func。完美。
然而,当我第二次向主体发射时,我看到主体有0个观察者。超时错误不合需要地删除了RXJS主题的所有当前观察者。但是,我不希望这种行为。我希望所有观察员都能继续订阅。
我该如何解决这个问题?
重要的代码行是......
console.log(this.getDocumentsSubject.observers.length);
第一次调用时返回1。
但是,在超时后第二次调用时,哪个有问题会返回0。
以下完整代码。
// RXJS SUBJECT AND ASSOCIATED OBSERVABLE
private getDocumentsSubject = new Subject<ElasticFilteredQuery>();
public getDocuments$ = this.getDocumentsSubject.asObservable().flatMap((elasticFilteredQuery: ElasticFilteredQuery) => {
let query = elasticFilteredQuery.toString();
// noinspection UnnecessaryLocalVariableJS
let restStream = this.http.post(BASE_URL + '_search', query, this.options)
.do(() => {
console.log('firing post');
})
.timeout(Config.http.timeout, new Error('timeout'))
.map((response: any) => {
return {
documents: response.json().hits.hits.map((hit: any) => {
return this.createDocumentResult(hit);
}),
numDocuments: response.json().hits.total,
elasticFilteredQuery
};
});
return restStream;
}).publish().refCount();
// EMIT TO RXJS SUBJECT - this is being called at the correct times
public getDocuments(elasticFilteredQuery: ElasticFilteredQuery) {
this.getDocumentsSubject.next(elasticFilteredQuery);
console.log('watch number of observables', this.getDocumentsSubject.observers.length); // Outputs 1 initially but 0 after a timeout
}
// SUBSCRIPTION
this.esQueryService.getDocuments$.subscribe((response: any) => {
console.log('XXXXX NEXT');
...
}, (err: any) => {
console.log('XXXXX error');
...
}, () => {
console.log('XXXXX completed');
}
);
答案 0 :(得分:2)
此答案完全基于以下假设:您希望将getDocuments$
用作永久流,只要新的查询进入,就会发出新数据。 (如果情况并非如此,那么答案可能对您没有帮助)
但是这不会像这样工作,因为无论何时在流上发出错误,Stream基本上都是死。 (另见this回答)
这是rxjs架构中的一个基本问题:错误应该抛在一次性进程上(如休息调用),但是数据流(如documents$
)通常会出现在确保已经处理了任何最终错误,并且永久流上发出的任何内容(next'ed
)都是可靠的&amp;有效数据。
所以我的建议是使用.catch()
来优雅地处理错误,并简单地跳过此调用文档的发送。
稍微偏离主题,可能不相关:
在任何情况下,对于休息呼叫都有一个非常不寻常的情况,如果你想节省服务器电源,那么我建议在服务器端处理这个问题。另一个非常常见的情况是,您可能只想接受响应,直到触发下一个查询以防止旧的,较慢的查询在呈现新的查询后显示,如果是这种情况,那么您可以使用简单的.takeUntil(this.getDocumentSubject)
:
this.http.post(BASE_URL + '_search', query, this.options)
.takeUntil(this.getDocumentSubject)
.do(...
作为替代方案,您可以使用switchMap
代替flatMap
答案 1 :(得分:1)
您所描述的是RxJS(以及所有Reactive Extensions)行为。这不是问题,也不是错误。这就是它应该如何运作的方式。任何错误或完整信号都会进行递归unsubscribe()
调用。你绝对不是第一个在SO上提出这个问题的人。
见类似:
使用主题时,这可能会产生意外行为,因为主题标记为&#34;已停止&#34;。请参阅https://github.com/ReactiveX/rxjs/blob/master/src/Subject.ts#L56。
使用catch()
运算符有一个重要的&#34; catch&#34;。此运算符允许您重新订阅到同一个Observable,这是您可能不想要的,因为它可能会触发更多HTTP请求,然后再次失败并进行无限循环。请注意,此运算符不会忽略错误。