在HTTP超时时保持订阅RXJS主题

时间:2016-12-06 16:19:55

标签: angular rxjs rxjs5

我有一个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');
  }
);

2 个答案:

答案 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上提出这个问题的人。

见类似:

使用catch()运算符有一个重要的&#34; catch&#34;。此运算符允许您重新订阅到同一个Observable,这是您可能不想要的,因为它可能会触发更多HTTP请求,然后再次失败并进行无限循环。请注意,此运算符不会忽略错误。