RX JS подписывайтесь, только если предыдущее значение не так велико, и мне действительно нужно лучшее - PullRequest
1 голос
/ 20 апреля 2020

У меня дорогой сервер ajax запрос, который имеет один вход (full: boolean). Если full равно false, сервер может вернуть либо частичный, либо полный ответ (response.isFull == true); но если full равно true, сервер будет возвращать полный ответ. Обычно частичный ответ достаточно хорош, но есть определенные условия, которые требуют полного ответа. Мне нужно избегать явного запроса полного ответа в максимально возможной степени, поэтому я подумал, что начну с BehaviorSubject, который я могу в конечном итоге скормить с помощью true, и объединю его с distinctUntilChanged, если мне когда-нибудь понадобится получить полный ответ. Это даст мне наблюдаемое с false изначально, и это может дать мне true, если я введу это в него:

const fullSubject = new BehaviorSubject<boolean>(false);

Тогда у меня есть функция, которая принимает логический параметр и возвращает можно наблюдать по запросу сервера (повторная попытка, преобразование и т. д. c.) Как уже говорилось, ответ может быть частичным или полным, но он может быть полным, даже если входной параметр был ложным по усмотрению сервера. Например:

interface IdentityData {
    ...
    isFull: boolean;
}

private getSimpleIdentity(full: boolean): Observable<IdentityData> {
    return Axios.get(`/api/identity${full?"?full=true":""}`)
    .pipe( ... retry logic ...,
        ... transformation logic ...,
        shareReplay(1) );
}

Мне нужно знать, как я могу объединить их так, чтобы выполнялось следующее:

  • Запрос к серверу должен выполняться не более двух раз.
  • Если первый ответ является полным ответом, дальнейшие запросы к серверу выполняться не должны.
  • Если первый ответ является частичным ответом, а true подается в fullSubject, полный должен быть запрошен ответ.

Ожидаемый результат от всего этого - наблюдаемая, которая испускает либо один полный ответ, либо частичный ответ и, когда его спрашивают, полный ответ.

Среда : Vue 2.6.11, Rx JS 6.5.5, Ax ios 0.19.2, TypeScript 3.7.5.

Заранее спасибо

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

Вот мой подход:

const fullSubject = new BehaviorSubject(false);

const src$ = fullSubject.pipe(
  switchMap(isFull => Axios.get('...')),
  take(2), // Server required at most twice
  takeWhile(response => !response.isFull, true), // When `isFull`, it will complete & unsubscribe -> no more requests to the server
  shareReplay(1),
);

src$.subscribe(() => { /* ... */ });

function getFullAnswer () {
  fullSubject.next(true);
}

takeWhile принимает второй аргумент , inclusive. Когда установлено значение true, когда функция предиката оценивается как false (например, isFull is true), она также отправит это значение. -

0 голосов
/ 20 апреля 2020

если я правильно понял

private getSimpleIdentity(): Observable<IdentityData> {
  return fullSubject.pipe(
    switchMap(full => Axios.get(`/api/identity${full ? "?full=true" : ""}`)),
    shareReplay(1),
  );
}

Использует retryWhen () оператор

const source = of("").pipe(map(() => Math.floor(Math.random() * 10 + 1)));

const example = source
  .pipe(
    tap((val) => console.log("tap", val)),
    map((val) => {
      //error will be picked up by retryWhen
      if (val !== 5) throw val;

      return val;
    }),
    retryWhen((errors) =>
      errors.pipe(
        tap(() => console.log("--Wait 1 seconds then repeat")),
        delay(1000)
      )
    )
  )
  .subscribe((val) => console.log("subscription", val));

/*
  output:
  tap 3
  --Wait 1 seconds then repeat
  tap 8
  --Wait 1 seconds then repeat
  tap 1
  --Wait 1 seconds then repeat
  tap 4
  --Wait 1 seconds then repeat
  tap 7
  --Wait 1 seconds then repeat
  tap 5
  subscription 5
*/
...