I want to be able to:
call a service only 30 times OR until a certain condition is met.
AND it must call it every 5 seconds
It would be nice if in the subscribe if I only see one console.log if that is possible.
In this case let us say until accuracy is less than 50. I stared with the following code and quickly exceeded the call stack. Can someone help with some real code? I put this question out here while I search for the answer myself. If I remove my ignorance I will post the answer. I am clearly out of my element here, but I will try to figure it out myself
public randomExample() {
this.randomNumber().pipe(
map((n) => {
console.log('map', n);
if (n.accuracy > 50) {
throw n;
}
return n;
}),
retryWhen(e =>
e.pipe(
tap(n => console.log('value to high', n))
)),
delayWhen(n => timer(5000))
).subscribe((n) => {
console.log('subscribed', n);
})
}
public randomNumber(): Observable<{accuracy:number}> {
const n =Math.floor(Math.random() * 100)
let value = {accuracy:n}
return of(value);
}
CodePudding user response:
function randomNumber(): { accuracy: number } {
const n = Math.floor(Math.random() * 100);
let value = { accuracy: n };
return value;
}
interval(5000)
.pipe(
scan((acc, curr) => acc 1, 0),
takeWhile((count) => count <= 30),
map(() => randomNumber()),
// tap((val) => console.log(val.accuracy)),
takeWhile((val) => val.accuracy < 50),
switchMap(() => of(Math.random() * 100).pipe(catchError(() => EMPTY)))
)
.subscribe((res) => {
console.log("subscribed", res);
});
Interval will call this every 5 seconds.
scan is a accumulator that accumulates count on every interval emit.
takeWhile as soon as count exceeds 30 will unsubscribe automatically.
takeWhile will keep this interval alive till randomNumber generator gives < 50 because we what we are saying there is unsubscribe is value is not less than 50.
if not unsubscribe above due to any condition we call our api via switch map and if API gives error we return an EMPTY observable via catch error call back so that polling continues.
subscribe block will only reach if api call completes.
Working link :- https://codesandbox.io/s/falling-flower-nblzz?file=/src/index.ts:219-726
In case you want to keep randomNumber as observable :-
function randomNumber(): Observable<{ accuracy: number }> {
const n = Math.floor(Math.random() * 100);
let value = { accuracy: n };
return of(value);
}
interval(5000)
.pipe(
scan((acc, curr) => acc 1, 0),
takeWhile((count) => count <= 30),
mergeMap(() => randomNumber()),
takeWhile((val) => val.accuracy < 50),
switchMap(() => of(Math.random() * 100).pipe(catchError(() => EMPTY)))
)
.subscribe((res) => {
console.log("subscribed", res);
});
Working link :- https://codesandbox.io/s/wonderful-hill-mtxi5?file=/src/index.ts:220-701
CodePudding user response:
You can use takeWhile
to check the index and the value, then switchMap
to call your API:
public randomExample() {
interval(500)
.pipe(
switchMap(() => this.randomNumber()),
takeWhile((n, index) => index < 30 && n.accuracy >= 50, true),
switchMap(n => {
// Call API and return observable
}),
)
.subscribe(n => {
console.log('subscribed', n)
})
}