RXJS 仅在以前的值不是那么好并且我真的需要一个更好的值时才订阅

RXJS subscribe only if previous value is not that great and I really need a better one

我有一个昂贵的服务器 ajax 请求,它有一个输入 (full: boolean)。如果 fullfalse,服务器可以 return 部分或完整响应 (response.isFull == true);但是如果 fulltrue,服务器 return 一个完整的响应。通常部分响应就足够了,但在某些情况下需要完整响应。我需要尽可能避免明确请求完整响应,所以我想我会从一个 BehaviorSubject 开始,我最终可以用 true 提供它,如果我可以将它与 distinctUntilChanged 结合起来永远需要得到完整的回应。这将给我一个带有 false 的可观察对象,如果我将其输入它可以给我 true

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

然后我得到一个函数,它接受一个布尔参数和 return 一个可观察到的服务器请求(重试、转换等)。如前所述,答案可以是部分的或完整的,但即使服务器判断输入参数为假,答案也可以是完整的。例如:

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

我需要知道如何将它们结合起来才能满足以下条件:

所有这一切的预期输出是一个可观察的,它发出一个完整响应或一个部分响应,并在被询问时发出一个完整响应。

环境:Vue 2.6.11、RxJS 6.5.5、Axios 0.19.2、TypeScript 3.7.5。

提前致谢

如果我没记错的话

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
*/

这是我的方法:

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

takeWhilesecond argumentinclusive。当设置为 true 时,当谓词函数的计算结果为 false(例如 isFull 为 true)时,它也会发送该值。 –