我是RxJS的新手,无法在以下用例中找到明确的答案:
在移动应用程序(Angular / Ionic)中,我需要(1)同时进行HTTP调用,并且仅在所有操作完成后才返回数据(例如$ q.all)。我想(2)如果调用正常工作,但其中一个满足特定条件的响应中存在嵌套值(即,用户未正确认证),则会引发错误。因为它是一个移动应用程序,所以我想(3)在调用无法正常运行(由于任何原因)的情况下进行几次重试。如果经过一定数量的重试尝试后呼叫仍然失败,我想(4)抛出错误。
根据我的研究,似乎forkJoin与q.all的工作原理相同。我有一个提供者,它返回以下内容(observableArray拥有http调用)。
return Observable.forkJoin(observableArray)
然后我可以输入一些运算符,这就是我开始努力的地方。为了检查嵌套值(2),我使用下划线方法遍历我的响应数组中的每个响应。这似乎一点都不干净。
为重试调用(3),我使用retryWhen和delayWhen。但是我不确定如何将其限制为3或4次尝试。
如果达到了限制,我将如何向订户(4)抛出错误?
.pipe(
map(
res => {
_.each(res, (obs) => {
if (!obs['success']) throw new Error('success was false')
})
}
),
retryWhen(attempts =>
attempts.pipe(
tap(err => console.log('error:', err),
delayWhen(() => timer(1000))
)
)
))
答案 0 :(得分:3)
这里有一些技巧可以使您的代码干净。
1。使用Observable.iif()
:
iif接受条件函数和两个Observable。订阅操作员返回的Observable时,将调用条件函数。根据当时返回的布尔值,消费者将订阅第一个Observable(如果条件为true)或第二个(如果条件为false)。
2。使用JavaScript数组本机的every()
:
every()方法测试数组中的所有元素是否通过提供的函数实现的测试。
3。使用take()
终止您的retryWhen
仅发射源Observable发出的第一个计数值。
因此您的代码归结为:
.pipe(
switchMap((res) => iif(
() => res.every(({success}) => success),
res,//if every element in res is successful, return it
throwError('success was false') //else if any of it is false, throw error.
)
),
retryWhen(err => err.delay(1000).take(4))
)
编辑:
如果您想在订阅时捕获错误,则需要重新抛出该错误。 .take()
实际上将终止序列,也就是完成序列:
.pipe(
switchMap((res) => iif(
() => res.every(({success}) => success),
res,//if every element in res is successful, return it
throwError('success was false') //else if any of it is false, throw error.
)
),
retryWhen(err => {
return errors.scan((errorCount, err) =>
(errorCount >= 4 ? //is retried more than 4 times?
throwError(err) : //if yes, throw the error
errorCount++ //else just increment the count
), 0);
})
)
答案 1 :(得分:0)
考虑的一种可能性是通过管道传递所需的各种运算符,例如retry
和map
进入observableArray
所包含的forkJoin
中的每个Observable中。
代码可能看起来与此类似
const observableArray = new Array<Observable<any>>();
const maxRetries = 4;
function pipeHttpObservable(httpObs: Observable<any>): Observable<any> {
return httpObs
.pipe(
map(data => data.success ? data : throwError('success was false')),
retryWhen(err => err.delay(1000).take(maxRetries))
)
}
observableArray.push(pipeHttpObservable(httpObs1));
observableArray.push(pipeHttpObservable(httpObs2));
.....
observableArray.push(pipeHttpObservable(httpObsN));
forkJoin(observableArray).subscribe(result => do stuff with the results)