concatMap,即使有多个订阅者,也只能共享一次播放一系列可观察的对象

时间:2019-10-05 14:08:54

标签: angular typescript rxjs

我正在尝试连续执行一些可观察性,这与concatMap一样,但是我希望它们只能执行一次,即使我有多个订阅者,我也尝试了share和shareReplay运算符,但没有一个似乎有效。

代码如下:

import { EMPTY, Observable, BehaviorSubject, of, from, concat, timer } from 'rxjs';
import { concatMap, map, switchMap, tap, filter, take, share, shareReplay, exhaust, publishLast, refCount } from 'rxjs/operators';


const refreshAccessToken = () => {
  console.log("Start refresh access token")
  return timer(2000);
}

const connect = () => {
  console.log("Start connect")
  return timer(3000)
}

const authent = () => {
  console.log("Start authent")
  return timer(2000)
}

let isAuthenticated = false;
let isExpired = true;

function initSocket(): Observable<any> {
  if (!isAuthenticated) {
    let observable$ = of(1);
    if (isExpired) {
      observable$ = refreshAccessToken();
    }
    return observable$.pipe(
      concatMap(() => connect()),
      concatMap(() => authent()),
      tap(() => {
        isAuthenticated = true;
        console.log("Tap")
      }),
      share()
    );
  }
  return of(1);
}


initSocket().subscribe(() => console.log("Finished 1"))

initSocket().subscribe(() => console.log("Finished 2"))

您可以在https://stackblitz.com/edit/rxjs-4memxw?embed=1&file=index.ts

中找到我的样本

结果是:

Start refresh access token
Start refresh access token
Start connect
Start connect
Start authent
Start authent
Tap
Finished 1
Tap
Finished 2

但是我要寻找的是:

Start refresh access token
Start connect
Start authent
Tap
Finished 1
Finished 2

也许这已经被回答了,但是我看不到我所缺少的,如果有人可以提供帮助,那就太好了。

编辑:

我会解释我的需求,也许我以错误的方式解决了这个问题。 我正在编写包装socket.io客户端的服务类,该类中每个发出或侦听socket.io事件的函数都必须检查我们是否已连接并验证到socket.io。

在每个订阅上,多个可观察对象需要执行以下操作:

  1. 检查是否已连接
  2. 如果不是,请检查访问令牌是否仍然存在 有效,如果是,请转到4
  3. 如果没有,请刷新访问令牌
  4. 创建socket.io连接并等待连接事件
  5. 在连接事件中发送access_token并等待响应
  6. 如果身份验证成功,则继续观察下一个

在这一系列可观察对象中,第一个订户将执行所有可观察对象,如果第二个订户在观察对象正在执行中等待相同结果时到达,则不要两次发起连接。

如果在连接完成后到达第三位或更多位,我们仍然需要检查变量isAuthenticated是否已更改,如果为false,则像第一个订阅者一样操作,如果为true,则继续。

希望它有助于阐明我在寻找什么。

1 个答案:

答案 0 :(得分:1)

您希望将数据分配给一个可观察对象,然后订阅该可观察对象,而不是调用initFunction(),后者创建的可观察对象与订阅者一样多。但是通过将数据分配给可观察的数据并进行订阅,可以防止这种情况的发生,也可以使用shareReplay

let obs$ = new Observable();

function initSocket(): void {
  if (!isAuthenticated) {
    let observable$ = of(1);
    if (isExpired) {
      observable$ = refreshAccessToken();
    }
    obs$ = observable$.pipe(
      concatMap(() => connect()),
      concatMap(() => authent()),
      tap(() => {
        isAuthenticated = true;
        console.log("Tap")
      }),
      shareReplay()
    );
  }
}

initSocket();

obs$.subscribe(() => console.log("Finished 1"))

obs$.subscribe(() => console.log("Finished 2"))

setTimeout(() => {
  obs$.subscribe(() => console.log("Finished 3 after 20 seconds"))
}, 20000)

STACKBLITZ