2017-04-13 142 views
4

我试图重复一个请求,直到响应中有使用RxJS的数据,此时我想调用成功(或失败)处理程序,但是我遇到了RxJS问题。这是我目前的做法:如何重复ajax请求,直到RxJS Observable满足条件?

// ... redux-observable action observable 
.mergeMap(() => 
    fetchData() 
    .repeatWhen(response => 
     response.takeWhile(({ data }) => !data.length) 
     .of(response) 
    ) 
) 
.map(successFunction) 
.catch(failureFunction); 

免责声明:我很新的RxJS ....

+1

那么,什么是预期的行为,什么是实际行为? – user3743222

回答

4

这听起来像你想压制阿贾克斯的结果和重试,直到你得到你想要的答复。我愿意做它像这样:所以首先我们检查,如果数据是空的,如果它是抛出一个错误

// observable that will re-fetch each time it is subscribed 
const request = Observable.defer(() => fetchData()); 

// each time request produces its value, check the value 
// and if it is not what you want, return the request 
// observable, else return an observable with the response 
// use switchMap() to then subscribe to the returned 
// observable. 
const requestWithRetry = request.switchMap(r => 
    r.data.length ? Observable.of(r) : requestWithRetry); 
+0

布兰登,我傻眼了。这是如何递归的?具有错误长度的第一个请求会导致'request'被再次订阅,导致'fetchData'的新执行并订阅该结果。但为什么这个结果会再次通过'switchMap'流动呢? – user3743222

+0

@ user3743222是的,你是对的。不知道我在想什么。第一个版本应该返回'requestWithRetry'。 :facepalm: – Brandon

+0

我现在明白了。很简约。现在我想知道堆栈是如何演变的。但在任何情况下,对于有限的再审,都不应该有任何问题。 – user3743222

3

空的数据是不是一个错误。 然后retryWhen可用于测试此错误并只要发生就重试。

.mergeMap(() => 
    fetchData() 
    .map(data => { 
     if (!data.length) { 
      throw 'no data'; 
     } 
     return data; 
    }) 
    .retryWhen(errors => errors.takeWhile(error => error === 'no data')) 
) 
.map(successFunction) 
.catch(failureFunction); 
+0

没有办法做到这一点没有投掷? – seitzej

+0

'repeatWhen'的问题是你没有访问'data'。 'repeatWhen'中的选择器只收到源的“onComplete”通知。因此,这使得它不适用于你的情况。 “repeatWhen”的逻辑是,你在该源完成时重新订阅源,然后在独立于该源的其他条件下重新订阅源。 'retrywhen'的优点是错误通知允许传递参数。 'onComplete'通知不是这样的情况 – user3743222

+0

@seitzej'retryWhen'只在潜在的observable进入错误状态AFAIK时才起作用,这可以在投掷时完成,为什么这是一个问题? –