用于多个异步调用的RxJS设计模式

用于多个异步调用的RxJS设计模式,rxjs,Rxjs,我是RxJS新手,在以下用例中未能找到明确的答案: 在移动应用程序(Angular/Ionic)中,我需要(1)同时进行HTTP调用,并且只在所有调用完成后返回数据(比如$q.all)。我想(2)抛出一个错误,如果调用工作正常,但其中一个响应中有一个嵌套值符合特定条件(即用户未正确验证)。因为它是一款移动应用程序,所以我想(3)如果通话无法正常工作(无论出于何种原因),我会尝试几次重试。如果经过一定次数的重试后,调用仍然失败,我想(4)抛出一个错误 根据我的研究,forkJoin的工作原理似乎与

我是RxJS新手,在以下用例中未能找到明确的答案:

在移动应用程序(Angular/Ionic)中,我需要(1)同时进行HTTP调用,并且只在所有调用完成后返回数据(比如$q.all)。我想(2)抛出一个错误,如果调用工作正常,但其中一个响应中有一个嵌套值符合特定条件(即用户未正确验证)。因为它是一款移动应用程序,所以我想(3)如果通话无法正常工作(无论出于何种原因),我会尝试几次重试。如果经过一定次数的重试后,调用仍然失败,我想(4)抛出一个错误

根据我的研究,forkJoin的工作原理似乎与q.all一样。我有一个提供程序返回以下内容(ObservalArray保存http调用)

返回可观察的forkJoin(可观察的array)
然后我可以引入一些操作员,这就是我开始挣扎的地方。为了检查嵌套值(2),我使用了下划线方法来迭代响应数组中的每个响应。这看起来一点也不干净

对于重试呼叫(3),我使用retryWhen和delayWhen。但我不确定如何将此限制为3次或4次尝试

如果达到限制,我将如何向订阅者返回错误(4)

.pipe(
地图(
res=>{
_.每个(res,(obs)=>{
如果(!obs['success'])抛出新错误('success为false')
})
}
),
重试时间(尝试次数=>
烟斗(
点击(err=>console.log('error:',err),
延迟时间(()=>计时器(1000))
)
)
))

这里有两个技巧可以让你的代码变得干净

1。用法:

iif接受一个条件函数和两个观察值。当操作员返回的可观测值被订阅时,将调用条件函数。根据此时返回的布尔值,使用者将订阅第一个可观测值(如果条件为真)或第二个可观测值(如果条件为假)

2。使用JavaScript数组本机的

every()方法测试数组中的所有元素是否通过了所提供函数实现的测试

3。用于在

仅发射源可观测对象发射的第一个计数值

因此,您的代码可以归结为:

.pipe(
开关图((分辨率)=>iif(
()=>res.every({success}=>success),
res,//如果res中的每个元素都成功,则返回它
TrowerRor('success was false')//否则,如果其中任何一个为false,则抛出错误。
)
),
retryWhen(err=>err.delay(1000.take)(4))
)
编辑:

如果要在订阅时捕获错误,则需要重新显示错误
.take()
实际上只是终止序列,即完成序列:

.pipe(
开关图((分辨率)=>iif(
()=>res.every({success}=>success),
res,//如果res中的每个元素都成功,则返回它
TrowerRor('success was false')//否则,如果其中任何一个为false,则抛出错误。
)
),
retryWhen(err=>{
返回错误。扫描((错误计数,错误)=>
(errorCount>=4?//是否重试4次以上?
throwError(err)://如果是,则抛出错误
errorCount++//否则只需增加计数
), 0);
})
)

这里有两个技巧可以让你的代码变得干净

1。用法:

iif接受一个条件函数和两个观察值。当操作员返回的可观测值被订阅时,将调用条件函数。根据此时返回的布尔值,使用者将订阅第一个可观测值(如果条件为真)或第二个可观测值(如果条件为假)

2。使用JavaScript数组本机的

every()方法测试数组中的所有元素是否通过了所提供函数实现的测试

3。用于在

仅发射源可观测对象发射的第一个计数值

因此,您的代码可以归结为:

.pipe(
开关图((分辨率)=>iif(
()=>res.every({success}=>success),
res,//如果res中的每个元素都成功,则返回它
TrowerRor('success was false')//否则,如果其中任何一个为false,则抛出错误。
)
),
retryWhen(err=>err.delay(1000.take)(4))
)
编辑:

如果要在订阅时捕获错误,则需要重新显示错误
.take()
实际上只是终止序列,即完成序列:

.pipe(
开关图((分辨率)=>iif(
()=>res.every({success}=>success),
res,//如果res中的每个元素都成功,则返回它
TrowerRor('success was false')//否则,如果其中任何一个为false,则抛出错误。
)
),
retryWhen(err=>{
返回错误。扫描((错误计数,错误)=>
(errorCount>=4?//是否重试4次以上?
throwError(err)://如果是,则抛出错误
errorCount++//否则只需增加计数
), 0);
})
)

<代码> > P>一种可能的考虑是将需要的各种运算符管起来,例如<代码>重试和<代码> MAP>代码>,将其包含在EngababLeLe> <代码>中的每个可观察到的代码中。 代码可能与此类似

const observearray=new Array();
常量maxRetries=4;
HttpObservable函数(httpObs:Observable):Observable{
返回httpObs
.烟斗(
map(data=>data.success?data:throwerr('success为false'),
retryWhen(err=>err.delay(1000).take(maxRetr