仅当还不是 Observable 时才转换为 Observable

Transform to Observable only if not already Observable

我有一张支票,需要合并 2 个支票:

  1. 第一个检查是可观察的,以判断用户是否已登录
  2. 第二个检查是一个函数,它可以 return 布尔值或 Observable

是否有更优雅的方式将一个值包装在一个可观察的对象中,如果它还不是可观察的? 或者当第二个是 Observable 时,有没有办法将第一个检查与第二个检查结合起来? 或者仍然以更有效的方式重构所有这些?

当然,此代码是模拟我在真实应用程序中获得的内容的示例(请参阅代码中的注释)。

const getRandomBool: () => boolean = () => Math.random() >= 0.5;
const getRandomCheck: () => boolean | Observable<boolean> = () => {
  return getRandomBool() ? getAsyncCheck() : getSyncCheck();
};


const myFunction = (): Observable<boolean> | boolean => {

  // First check telling if user is logged, which the UserService returns as Observable<boolean>
  return of(getRandomBool())
    .pipe(
      mergeMap((isLogged) => {
        // This is the check which can be either boolean or Observable<boolean>
        const myCheck = getRandomCheck();
        
        return isLogged
            ? ​i​if(() => typeof myCheck === 'boolean', of(myCheck), myCheck)
            : of(!1)
     ​})
   ​)
};
``

There is isObservable method

例子

const { of, iif, pipe, isObservable , operators: { mergeMap } } = rxjs;

const getAsyncCheck = () => of(Boolean(Math.floor(Math.random() * 2)));
const getSyncCheck = () => Boolean(Math.floor(Math.random() * 2));
const getRandomBool = () => Boolean(Math.floor(Math.random() * 2));
const getRandomCheck = () => {
  return getRandomBool() ? getAsyncCheck() : getSyncCheck();
};


const myFunction = () => {


  return of(getRandomBool())
    .pipe(
      mergeMap((isLogged) => {

        const myCheck = getRandomCheck();
        const result = isLogged ? iif(() => isObservable(myCheck), myCheck, of(myCheck)) : of(false);
        return result;
     })
   ).subscribe(result => {
    console.log(result)
  })
};

myFunction();
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>

我会强制 randomCheck 到 observable,然后使用 exhaustMap 来处理返回正确的 observable; of(false)isLogged = falserandomCheck$ 否则:

const myFunction = (): Observable<boolean> => {
  const randomCheck$ = isObservable(randomCheck) ? randomCheck : of(randomCheck);

  return getIsLogged().pipe(
    exhaustMap(isLogged => isLogged ? randomCheck$ : of(false)),
    // take(1)
  );
};

如果getIsLogged()没有完成,我认为你需要使用take(1)来angular守卫。

如果“myCheck”是 Observable 并使用 forkJoin,先检查如何?

const myFunction: () => Observable<boolean> = () => {
  let myCheck = getRandomCheck();
  myCheck = isObservable(myCheck) ? myCheck : of(myCheck);

  return forkJoin([of(getRandomBool()), myCheck])
  .pipe(
    map(([logged, yourCheck]) => {

      return logged ? yourCheck : !1;
    })
  )
}

编辑 正如 BizzyBob 所建议的那样,如果 myCheck 是异步的并且跨度很大,它可能会毫无意义地影响整个执行。 所以我们可以使用switchMap来避免这个问题

const myFunction: () => Observable<boolean> = () => {
  let myCheck = getRandomCheck();
  myCheck = isObservable(myCheck) ? myCheck : of(myCheck);

  return of(getRandomBool())
  .pipe(
    switchMap((logged: boolean) => {

      return logged ? myCheck : of(!1);
    })
  )
}