我对observables有一个优化问题:
我有两个接受用户名和密码的控件。当密码字段的值发生变化(带有去抖动)时,我想调用一个返回查询结果的可观察对象的服务方法,并用这些值填充模型。
返回的observable在服务错误的情况下抛出异常。但是我想在这种情况下用空数组填充模型。
我最初的实施:
this.passwordControl.valueChanges
.debounceTime(500)
.filter(_ => this.usernameControl.valid && !this.usernameControl.pristine)
.map((password) => new RequestAuthentication(this.usernameControl.value, password))
.mergeMap(auth => this.orgService.getOrganizations(auth))
.catch(_ => {
return Observable.of([]);
})
.subscribe(orgs => {
this.organizations = orgs;
});
缺点是当执行catch函数时,我返回一个完成流的有限observable,我不能再听取这些更改了。
我的解决方案是嵌套observables:
this.passwordControl.valueChanges
.debounceTime(500)
.filter(_ => this.usernameControl.valid && !this.usernameControl.pristine)
.map((password) => new RequestAuthentication(this.usernameControl.value, password))
.subscribe(auth => {
this.orgService.getOrganizations(auth)
.catch(_ => Observable.of([]))
.subscribe(orgs => {
this.organizations = orgs;
});
});
但这似乎没有反应......我该如何避免这些嵌套的observable并保持代码干净?
答案 0 :(得分:0)
一般不建议在另一个subscribe()
内调用subscribe()
,因为你只是用“subscribe hell”交换“callback hell”。此外,您正在丢失来自父Observable链的error
和complete
信号。尽管如此,你总是可以避免它。
因此,如果您不希望在发生错误时结束链,那么有一些运营商可以帮助您。具体来说:retry()
和retryWhen()
(也是onErrorResumeNext()
),可能还有更多。
如果您在发生错误信号时不想做任何事情,请使用retry()
代替catch()
:
.mergeMap(...)
.retry()
.subscribe(orgs => {
this.organizations = orgs;
});
如果您仍希望能够执行某些副作用(通知用户或其他),请在.do()
之前使用retry()
:
.mergeMap(...)
.do(null, e => ...)
.retry()
.subscribe(orgs => {
this.organizations = orgs;
});