在可管道 rxjs 运算符的组合管道中捕获错误
Posted
技术标签:
【中文标题】在可管道 rxjs 运算符的组合管道中捕获错误【英文标题】:Catch error in combined pipe of pipeable rxjs operators 【发布时间】:2018-04-28 21:08:53 【问题描述】:我们刚刚将我们的一个应用程序升级到 Angular 5,并开始转换为 rxjs v5.5 中引入的lettable operators。
因此,我们使用 .pipe()
运算符将可观察管道重写为新语法。
我们之前的代码看起来像这样,在.switchMap()
内部有一个.catch()
,以便在抛出错误时不会中断效果的运行。
@Effect()
loadData$ = this.actions$
.ofType(LOAD_DATA)
.map((action: LoadData) => action.payload)
.withLatestFrom(this.store.select(getCultureCode))
.switchMap(([payload, cultureCode]) => this.dataService.loadData(payload, cultureCode)
.map(result =>
if (!result)
return new LoadDataFailed('Could not fetch data!');
else
return new LoadDataSuccessful(result);
)
.catch((err, caught) =>
return Observable.empty();
);
);
如果在调用dataService
时出现错误,它将被捕获并处理(此处简化了错误处理)。
有了.pipe()
的新语法和使用,我们现在有了这个
@Effect()
loadData$ = this.actions$
.ofType(LOAD_DATA)
.pipe(
map((action: LoadData) => action.payload),
withLatestFrom(this.store.select(getCultureCode)),
switchMap(([payload, cultureCode]) => this.dataService.loadData(payload, cultureCode)),
map(result =>
if (!result)
return new LoadDataFailed('Could not fetch data!');
else
return new LoadDataSuccessful(result);
)
);
如何使用新语法以类似的方式捕获可观察管道中抛出的任何错误?
【问题讨论】:
重构后,您将map
移出switchMap
投影,因此任何错误都会关闭外部流。类似:switchMap(([payload, cultureCode]) => this.dataService.loadData(payload, cultureCode).pipe(map..., catch...))
应该可以完成这项工作。
效果很好@arturgrzesiak!将其发布为答案,我会接受! :)
【参考方案1】:
重构后,您将map
移出switchMap
投影,因此任何错误都会关闭外部流。为了使两个流保持相同,您需要在投影本身中使用pipe
,如下所示:
import empty from 'rxjs;
// ...
@Effect()
loadData$ = this.actions$
.ofType(LOAD_DATA)
.pipe(
map((action: LoadData) => action.payload),
withLatestFrom(this.store.select(getCultureCode)),
switchMap(([payload, cultureCode]) =>
this.dataService.loadData(payload, cultureCode)
.pipe(
map(result =>
if (!result)
return new LoadDataFailed('Could not fetch data!');
else
return new LoadDataSuccessful(result);
),
catchError((err, caught) =>
return empty;
)
)
)
);
【讨论】:
这完全符合我的预期,尽管catch
已重命名为catchError
!谢谢!
我必须这样做:import empty from 'rxjs;
,然后是 rjxs v6 中的empty()
仅供参考,empty() 已被弃用,取而代之的是 EMPTY 常量: import EMPTY from "rxjs/internal/observable/empty"
@jk。不确定 - 你能粘贴一个发布说明的链接吗?我在6.3.3
,有empty
。此外,直接从rxjs/internal
导入对我来说似乎有点奇怪。
@artur grzesiak 链接到我所看到的:github.com/ReactiveX/rxjs/blob/master/src/internal/observable/… 看起来确实很奇怪,但它是 intellij 中唯一没有弃用的。我在 rxjs-compat@6.3.2 和 rxjs@6.2.0。不确定我是否需要这两个..【参考方案2】:
你也可以这样做。
import of from 'rxjs';
@Effect()
loadData$ = this.actions$
.ofType(LOAD_DATA)
.pipe(
map((action: LoadData) => action.payload),
withLatestFrom(this.store.select(getCultureCode)),
switchMap(([payload, cultureCode]) =>
this.dataService.loadData(payload, cultureCode)
.pipe(
map(result =>
if (!result)
return new LoadDataFailed('Could not fetch data!');
else
return new LoadDataSuccessful(result);
),
catchError(err => of('error', err))
)
)
);
【讨论】:
以上是关于在可管道 rxjs 运算符的组合管道中捕获错误的主要内容,如果未能解决你的问题,请参考以下文章
如何使用jasmine-marbles测试rxjs管道中的timeout()
为啥我应该在 Angular 订阅中使用 select 和管道?