angular - RxJS mergeMap 操作符内部的错误处理
问题描述
当我使用 Angular HttpClient 发出 GET 请求时,我得到一个 observable 返回并在 RxJS 运算符 mergeMap 中处理它。
现在它一次又一次地抛出一个 404,我想抓住它。最后,浏览器控制台中不应出现任何错误消息,并且应使用流的下一个值处理管道。
有没有可能?我没有用 catchError() 管理它。
这是我的代码的简化版本:
...
this.service1.getSomeStuff().pipe(
mergeMap((someStuff) => {
return from(stuff);
}),
mergeMap((stuff) => {
return this.service2.getMoreStuff(stuff.id); // Here I need some error handling, if 404 occurs
}),
mergeMap((things) => {
return from(things).pipe(
mergeMap((thing) => {
if (allLocations.some(x => x.id === metaData.id)) {
return this.service2.getMore(thing.id, thing.type, thing.img_ref);
}
}),
map((thing) => {
...
更新:添加了 catchError() 方法
我这样尝试过,但是没有检测到错误,并且下一个 mergeMap 不起作用(IDE 不再识别诸如thing.id、thing.type、thing.img_ref 之类的参数):
...
this.service1.getSomeStuff().pipe(
mergeMap((someStuff) => {
return from(stuff);
}),
mergeMap((stuff) => {
return this.service2.getMoreStuff(stuff.id).pipe(
catchError(val => of(`Error`))
);
}),
mergeMap((things) => {
return from(things).pipe(
mergeMap((thing) => {
if (allLocations.some(x => x.id === metaData.id)) {
return this.service2.getMore(thing.id, thing.type, thing.img_ref);
}
}),
map((thing) => {
...
解决方案
您需要使用retry
or retryWhen
(名称非常不言自明)——这些运算符将重试失败的订阅(一旦发出错误,重新订阅源 observable。
要id
在每次重试时提高 - 您可以将其锁定在一个范围内,如下所示:
const { throwError, of, timer } = rxjs;
const { tap, retry, switchMap } = rxjs.operators;
console.log('starting...');
getDetails(0)
.subscribe(console.log);
function getDetails(id){
// retries will restart here
return of('').pipe(
switchMap(() => mockHttpGet(id).pipe(
// upon error occurence -- raise the id
tap({ error(err){
id++;
console.log(err);
}})
)),
retry(5) // just limiting the number of retries
// you could go limitless with `retry()`
)
}
function mockHttpGet(id){
return timer(500).pipe(
switchMap(()=>
id >= 3
? of('success: ' + id)
: throwError('failed for ' + id)
)
);
}
<script src="https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js"></script>
请注意,最好有条件retry
仅对404
错误进行重试。这可以通过retryWhen
例如来实现
// pseudocode
retryWhen(errors$ => errors$.pipe(filter(err => err.status === '404')))
查看这篇关于 rxjs 中的错误处理的文章,以更丰富地使用retry
和retryWhen
.
希望这可以帮助
更新:还有其他方法可以实现:
const { throwError, of, timer, EMPTY } = rxjs;
const { switchMap, concatMap, map, catchError, take } = rxjs.operators;
console.log('starting...');
getDetails(0)
.subscribe(console.log);
function getDetails(id){
// make an infinite stream of retries
return timer(0, 0).pipe(
map(x => x + id),
concatMap(newId => mockHttpGet(newId).pipe(
// upon error occurence -- suppress it
catchError(err => {
console.log(err);
// TODO: ensure its 404
// we return EMPTY, to continue
// with the next timer tick
return EMPTY;
})
)),
// we'll be fine with first passed success
take(1)
)
}
function mockHttpGet(id){
return timer(500).pipe(
switchMap(()=>
id >= 3
? of('success: ' + id)
: throwError('failed for ' + id)
)
);
}
<script src="https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js"></script>
推荐阅读
- arrays - 每天查找数组 React
- string - 如何在 Scala 中将棋子与字符串分开?
- c# - 我用 DI 注入的服务有很多方法。有没有办法让这些容易找到?
- java - 如何在 Spark SQL Java 中将 CSV 类型字符串转换为数据框?
- spring - 无法创建简单的spring Boot Gateway api
- angular - 找出 Angular 项目中使用的更改事件的 Typescript 类型
- javascript - 如何用 Jest Javascript React Native 模拟“替换”功能?
- php - 如何使用 PHP 或 JavaScript 获取特定条件的当前 URL?
- delphi - Delphi 无效的类类型转换
- java - 哪种数据类型可用于在 Hibernate/jpa 中创建主键变量?