我正在尝试在HTTP调用中使用retryWhen.
尝试使用时,它完美地工作:
return this.http.get(`${environment.apiUrl}/track/${this.user.instance._id}/${this.currentPlayer.playlist.id}/next?s=${this.playerCounter}`,options) .timeout(500,new TimeoutError(`Timeout trying to get next track. [instanceId=${this.user.instance._id}]`)) .retryWhen(attempts => { return Observable.range(1,3).zip(attempts,i => i).flatMap(i => 3 === i ? Observable.throw(attempts) : Observable.timer(i * 1000)); })
如果出现超时错误,最多会尝试3次.
但是,总是有一个buuut,我想让它更抽象地用于各种用例,为此,我必须检查错误的类型.
只会重试TechnicalErros.
所以我尝试了这个没有成功.
.retryWhen(attempts => { return attempts.flatMap(error => { if(error instanceof TechnicalError) { return Observable.range(1,i => i).flatMap(i => 3 === i ? Observable.throw(attempts) : Observable.timer(i * 1000)); } else { Observable.throw(error); } }); })
它在第一次尝试时停止,并且不执行Observable.timer(),也不执行Observable.throw().
我几乎可以肯定问题是关于第一个flatMap,我已经尝试使用mergeMap,但没有成功.
提前致谢!
解决方法
在RxJS 5中,flatMap()只是mergeMap():)的别名.
问题在于您使用retryWhen()运算符的回调方式.它只被调用一次,然后每当一个错误信号到达时它被推送到从这个回调返回的Observable.
在你的第二个例子中,你从attempts.flatMap返回Observable,然后再次使用.zip(attempts,i => i)订阅回调.但是这个zip运算符永远不会被调用,因为它在calculate.flatMap已经消耗了值之后被调用.这就是为什么Observable.range(1,3)始终从头开始.
我知道这看起来令人困惑.请注意:
> retryWhen()的回调只被调用一次.
>每次出现错误时都会调用attempt.flatMap()的回调.
因此,您只需重新构建代码,例如:
var source = Observable.create(obs => { obs.next(1); obs.next(2); obs.error(new TechnicalError('error from source')); }) .retryWhen(attempts => { console.log('retryWhen callback'); let count = 0; return attempts.flatMap(error => { if (error instanceof TechnicalError) { console.log(error); return ++count >= 3 ? Observable.throw(error) : Observable.timer(count * 1000); } else { return Observable.throw(error); } }); }) .subscribe( val => console.log(val),err => console.log('subscribe error',err),_ => console.log('complete') );
这打印到控制台:
1 2 retryWhen callback TechnicalError { msg: 'error from source' } 1 2 TechnicalError { msg: 'error from source' } 1 2 TechnicalError { msg: 'error from source' } subscribe error TechnicalError { msg: 'error from source' }