Javascript RxJS每x秒从数组中发出一个值,使用该值调用一个函数,如果失败,请重试

Javascript RxJS每x秒从数组中发出一个值,使用该值调用一个函数,如果失败,请重试,javascript,rxjs,rxjs5,Javascript,Rxjs,Rxjs5,我有一个数组,值的类型是无关的。我想做的是每x秒发出一个值,用该值调用一个函数,如果该函数由于某种原因失败,请在y秒后重试(可以是一个简单的常量,这里不需要任何增量) 到目前为止我所拥有的 Rx.Observable .interval(500) .take(arr.length) .map(idx => arr[idx]) .flatMap(dt => randomFunc(dt)) .catch(e => conosle.log(e)

我有一个数组,值的类型是无关的。我想做的是每x秒发出一个值,用该值调用一个函数,如果该函数由于某种原因失败,请在y秒后重试(可以是一个简单的常量,这里不需要任何增量)

到目前为止我所拥有的

Rx.Observable
    .interval(500)
    .take(arr.length)
    .map(idx => arr[idx])
    .flatMap(dt => randomFunc(dt))
    .catch(e => conosle.log(e))
    .retry(5)
    .subscribe();

function randomFunc(dt) {
    return Rx.Observable.create(observer => {
        if (dt === 'random') {
            return observer.error(`error`);
        } else {
            return observer.next();
        }
    });
}
但这里有两个问题:

1:当
randomFunc
返回错误时,整个链似乎重新开始。我只需要失败的一个来重试

2:
catch
从不实际记录任何错误,即使它似乎会在出现错误时重试

对于第一个问题,我尝试了
switchMap
而不是
flatMap
,如下所示:

Rx.Observable
    .interval(500)
    .take(arr.length)
    .map(idx => arr[idx])
    .switchMap(dt => randomFunc(dt)
        .catch(e => conosle.log(e))
        .retry(5)
    )
    .subscribe();
通过这种方式,它似乎只重试了失败的部分,但仍然没有记录任何错误,我甚至不确定
switchMap
在这里是否好(我真的是一个Rx noob)

任何帮助都将不胜感激,谢谢

randomFunc
返回错误时,整个链似乎开始运行 结束我只需要失败的一个来重试`

在RxJs中,当将观测值组合在一起时,错误也会传播,未捕获的错误会导致取消订阅

您在
开关映射中使用catch的想法是正确的。虽然
switchMap
一次只展平一个可观测值,但当下一个值被映射时,上一个可观测值将被取消订阅(它被关闭)

//可从数组中观察到
从(arr)可观察到的接收
.concatMap(值=>
//在每个值之间设置500毫秒的延迟
Rx.Observable.timer(500).map(=>value)
)
.flatMap(dt=>
随机函数(dt)
.retryWhen(错误=>
错误
.do(err=>console.error(err))
//最多重试5次
.采取(5)
//500毫秒后重试
.延迟(500)
)
)
.subscribe();
catch实际上从不记录任何错误,即使它似乎在上重试 错误

传递给catch的函数应返回一个可观察的值,例如:

Observable.throw(新错误())
.catch(e=>
(控制台错误(e),可观察到(‘备份值’)
)
.subscribe();

有几件事需要注意。
retry()
操作符只需重新订阅其源代码,因此如果不想再次开始整个迭代,可以将/concat异步函数合并到链中

Rx.Observable.from(arr)
  .concatMap(val => {
    let attempts = 0;

    return Rx.Observable.of(val)
      .delay(500)
      .concatMap(val => randomFunc(val)
        .catch((err, caught) => {
          console.log('log error');
          if (attempts++ === 1) {
            return Rx.Observable.of(err);
          } else {
            return caught;
          }
        })
      );

  })
  .subscribe(val => console.log(val));

function randomFunc(dt) {
  return Rx.Observable.create(observer => {
    if (dt === 'random') {
      observer.error(`error received ${dt}`);
    } else {
      observer.next(dt);
      observer.complete();
    }
  });
}
见现场演示:

这将打印到控制台:

1
2
3
4
log error
log error
error received random
6
7
8
9
10
catch()
操作符是最重要的部分。其选择器函数具有两个参数:

  • err
    -发生的错误
  • 捕获
    -原始可观察到的

如果我们从选择器函数返回
catch
,我们只需重新订阅可观察的源代码(这与
retry(1)
)相同)。由于要记录每个错误消息,我们必须使用
catch()
,而不仅仅是
retry()
。通过返回(err)
Rx.Observable.of(err)
我们进一步传播错误,然后订阅者将收到该错误作为
下一个
通知。我们也可以只返回
Observable.empty()
来忽略错误。

catch
可能没有记录,因为控制台拼写错误:-)conosle=>console