I have multiple URLs that contain information. I have an ID I am trying to look up but do not know which URL contains the information I need. I am trying to call each URL and whichever returns a valid response first, use that and cancel the other calls.
I have attempted to use race()
to do this, but have run into an issue where it will take the result from the Observable
to complete, even if that Observable
has not emitted any values (or they have been filtered out). I have tried to resolve this by doing .concat(never())
on each Observable
, but then it seems like race()
does not cancel the Observables after the fact, meaning I cannot reuse them for subsequent calls.
const urls = ['url1', 'url2', 'url3']
private getItem(id: string): Observable<string> {
return race(
...this.makeUrlCalls(id),
timer(10000).pipe(flatMap(() => of(''))),
)
}
private makeUrlCalls(id: string): Array<Observable<string>> {
return urls.map(url => {
return this.http.get<any>(url + id).pipe(
map(({items: [item]}) => item),
filter(Boolean),
concat(never()),
retry(2),
)
})
}
What I want to happen is that whenever a URL returns a result, the first one that has a valid value (non-empty array called item) is returned from the race()
call.
Any help is greatly appreciated!
You can use merge
to combine all the Http calls into a single Observable
, and then use first
on the combined Observable
with a predicate function. The combined Observable
will only emit the first inner Observable
emission that passes the predicate.
const urls = ['url1', 'url2', 'url3']`;
private getItem(id: string): Observable<string> {
return merge(...this.makeUrlCalls(id))
.pipe(first(s => !!s.length))
}
private makeUrlCalls(id: string): Array<Observable<string>> {
return urls.map(url => {
return this.http.get<any>(url + id).pipe(
map(({items: [item]}) => item),
concat(never()),
retry(2),
)
})
}
I took the filter
off the mapped array, because that could be handled with the higher-level merge
operator. In fact, the filter
method could block emissions in conjunction with first()
instead of passing a predicate method to first
.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments