Как вызвать несколько URL-адресов и обрабатывать только первое значение, которое возвращается с помощью RxJS? - PullRequest
0 голосов
/ 12 февраля 2019

У меня есть несколько URL, которые содержат информацию.У меня есть идентификатор, который я пытаюсь найти, но не знаю, какой URL содержит нужную мне информацию.Я пытаюсь вызвать каждый URL-адрес и в зависимости от того, что вернет правильный ответ первым, используйте его и отмените другие вызовы.

Я пытался использовать race() для этого, но столкнулся с проблемой, из-за которой он будетдля завершения возьмите результат из Observable, даже если этот Observable не выдал никаких значений (или они были отфильтрованы).Я попытался решить эту проблему, выполнив .concat(never()) для каждого Observable, но затем кажется, что race() не отменяет Observables после факта, то есть я не могу использовать их для последующих вызовов.

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),
        )
    })
}

Я хочу, чтобы всякий раз, когда URL-адрес возвращал результат, первое, которое имеет допустимое значение (непустой массив с именем item), возвращается из вызова race().

Любая помощь очень ценится!

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

Вы можете использовать merge, чтобы объединить все вызовы Http в один Observable, а затем использовать first в комбинированном Observable с функцией предиката.Объединенный Observable будет испускать только первое внутреннее Observable излучение, которое передает предикат.

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),
        )
    })
}

Я снял filter с сопоставленного массива, потому что это может быть обработано с более высоким уровнемmerge оператор.Фактически, метод filter может блокировать выбросы вместе с first() вместо передачи метода предиката в first.

0 голосов
/ 12 февраля 2019

вы можете использовать rxjs takeUntil для выполнения других ожидающих запросов http, что-то вроде следующего:

let flag$ = new Subject();
someHttp
  .pipe(
    ...
    takeUntil(flag$)
  );
race(...)
  .subscribe(() => {
    // or finalize
    flag$.next();
  });
...