RxJS:Auto(dis)connect on(un)订阅Websockets和Stomp

RxJS:Auto(dis)connect on(un)订阅Websockets和Stomp,rxjs,reactive-programming,rxjs5,reactivex,reactive,Rxjs,Reactive Programming,Rxjs5,Reactivex,Reactive,我正在为Stomp over WebSocket构建一个小小的RxJS包装器,它已经可以工作了 但是现在我想到了一个非常酷的特性,它可能(如果我错了,希望能纠正我的错误)很容易用RxJS实现 当前行为: 如您所见,我必须等待state==“CONNECTED”才能订阅subscribedestation(…)。否则我会从Stomp库中得到一个错误 新行为: 下一个实现应该会让用户更容易。以下是我的想象: myStompWrapper.configure("/stomp_endpoint");

我正在为Stomp over WebSocket构建一个小小的RxJS包装器,它已经可以工作了

但是现在我想到了一个非常酷的特性,它可能(如果我错了,希望能纠正我的错误)很容易用RxJS实现

当前行为: 如您所见,我必须等待
state==“CONNECTED”
才能订阅
subscribedestation(…)
。否则我会从Stomp库中得到一个错误

新行为: 下一个实现应该会让用户更容易。以下是我的想象:

myStompWrapper.configure("/stomp_endpoint");

var subscription = myStompWrapper.subscribeDestination("/foo")
    .subscribe(msg => console.log(msg));

// ... and some time later:
subscription.unsubscribe();
它应该如何在内部工作:

myStompWrapper.configure("/stomp_endpoint");
myStompWrapper.connect();

myStompWrapper.observeDestination("/foo")
    .subscribe(..);

myStompWrapper.observeDestination("/bar")
    .subscribe(..);
myStompWrapper.configure("/stomp_endpoint");

let subscription1 = myStompWrapper.observeDestination("/foo")
    .subscribe(..); // execute connect(), because this
                    // is the first subscription

let subscription2 = myStompWrapper.observeDestination("/bar")
    .subscribe(..);

subscription2.unsubscribe();
subscription1.unsubscribe(); // execute disconnect(), because this 
                             // was the last subscription
  • configure
    只能在
    断开连接时调用
  • 调用
    subscribedestation
    时,有两种可能性:
  • 如果
    已连接
    :只需订阅目的地即可
  • 如果
    断开连接
    :首先调用
    connect()
    ,然后订阅目标
  • 调用
    unsubscribe
    时,有两种可能:
  • 如果这是最后一次订阅:调用
    disconnect()
  • 如果这不是最后一次订阅:什么也不做
  • 我还不知道如何到达那里,但这就是为什么我在这里问这个问题

    提前谢谢

    编辑:更多代码、示例和解释 当调用configure()未断开连接时,它应该抛出一个
    错误。但这没什么大不了的

    stompClient.connect(..)是非阻塞的。它有一个
    onSuccess
    回调:

    public connect() {
      stompClient.connect({}, this.onSuccess, this.errorHandler);
    }
    
    public onSuccess = () => {
      this.state.next(State.CONNECTED);
    }
    
    observeDestination(..)订阅Stomp消息频道(=目的地),并返回一个
    Rx.observeable
    ,然后可用于取消订阅此Stomp消息频道:

    public observeDestination(destination: string) {
      return this.state
          .filter(state => state == State.CONNECTED)
          .flatMap(_ => Rx.Observable.create(observer => {
            let stompSubscription = this.client.subscribe(
                destination,
                message => observer.next(message),
                {}
            );
    
            return () => {
              stompSubscription.unsubscribe();
            }
          }));
    }
    
    可以这样使用:

    myStompWrapper.configure("/stomp_endpoint");
    myStompWrapper.connect();
    
    myStompWrapper.observeDestination("/foo")
        .subscribe(..);
    
    myStompWrapper.observeDestination("/bar")
        .subscribe(..);
    
    myStompWrapper.configure("/stomp_endpoint");
    
    let subscription1 = myStompWrapper.observeDestination("/foo")
        .subscribe(..); // execute connect(), because this
                        // is the first subscription
    
    let subscription2 = myStompWrapper.observeDestination("/bar")
        .subscribe(..);
    
    subscription2.unsubscribe();
    subscription1.unsubscribe(); // execute disconnect(), because this 
                                 // was the last subscription
    
    现在我想摆脱
    myTompRapper.connect()
    。当第一个用户通过调用
    observeDestination(..).subscribe(..)
    进行订阅时,代码应自动调用
    this.connect()
    ,当最后一个用户调用
    unsubscribe()
    时,代码应调用
    this.disconnect()

    示例:

    myStompWrapper.configure("/stomp_endpoint");
    myStompWrapper.connect();
    
    myStompWrapper.observeDestination("/foo")
        .subscribe(..);
    
    myStompWrapper.observeDestination("/bar")
        .subscribe(..);
    
    myStompWrapper.configure("/stomp_endpoint");
    
    let subscription1 = myStompWrapper.observeDestination("/foo")
        .subscribe(..); // execute connect(), because this
                        // is the first subscription
    
    let subscription2 = myStompWrapper.observeDestination("/bar")
        .subscribe(..);
    
    subscription2.unsubscribe();
    subscription1.unsubscribe(); // execute disconnect(), because this 
                                 // was the last subscription
    

    我同意你建议把代码塞进MyTompRapper的新家里会更快乐

    我仍然建议使用像
    observeDestination
    这样的名称,而不是
    subscribedestinition(“/foo”)
    ,因为您实际上并不是从该方法订阅,而是完成您的可观察链

  • configure()
    只能在
    断开连接时调用

    如果在未断开连接的情况下调用它,您不需要在此处指定应该发生什么。由于您在这里似乎没有返回任何要使用的值,因此我假设您打算在异常状态不方便时抛出异常。为了跟踪这些状态,我将使用一个
    behavior subject
    ,它以
    DISCONNECTED
    的初始值开始。您可能希望将状态保持在
    observeDestination
    中,以决定是否抛出异常

  • 如果已连接:只需订阅目标

    如果断开连接:首先调用connect(),然后订阅目标

    正如我前面提到的,如果订阅不是发生在
    subscribedestinition(“/foo”)
    中,而是你只是构建了你的可观察链,我想你会更快乐。在某些情况下,您只需要调用
    connect()
    ,我只需要在包含状态条件的可观察链中使用
    .do()
    调用

  • 要使用rx-y逻辑,您可能需要调用
    disconnect()
    ,作为observable unsubscribe的一部分,并简单地返回一个共享的refcounted observable。这样,每个新订户就不会重新创建新的订阅,而是
    。refCount()
    将对可观察链进行单个订阅,并且
    取消订阅()
    一旦下游不再有订户

  • 假设消息以的形式传入,则
    mytompwrapper
    中的observedData$
    作为
    mytompwrapper
    的一部分,我的建议代码将如下所示:

    observeDestination() {
      return Rx.Observable.create(function (observer) {
         var subscription = this.getState()
                 .filter(state => state == "CONNECTED")
                 .do(state => state ? this.connect() : Observable.of(true))
                 .switchMap(this.observedData$)
                 .refCount();
                 .subscribe(value => {
                   try {
                     subscriber.next(someCallback(value));
                   } catch(err) {
                     subscriber.error(err);
                   }
                 },
                 err => subscriber.error(err),
                 () => subscriber.complete());
    
     return { unsubscribe() { this.disconnect(); subscription.unsubscribe(); } };
    }
    
    因为我丢失了您的一些代码,所以我允许自己不测试代码。但希望它能说明并呈现我在回答中提到的概念。

    我同意你建议把代码塞进MyTompRapper的新家里会更快乐

    我仍然建议使用像
    observeDestination
    这样的名称,而不是
    subscribedestinition(“/foo”)
    ,因为您实际上并不是从该方法订阅,而是完成您的可观察链

  • configure()
    只能在
    断开连接时调用

    如果在未断开连接的情况下调用它,您不需要在此处指定应该发生什么。由于您在这里似乎没有返回任何要使用的值,因此我假设您打算在异常状态不方便时抛出异常。为了跟踪这些状态,我将使用一个
    behavior subject
    ,它以
    DISCONNECTED
    的初始值开始。您可能希望将状态保持在
    observeDestination
    中,以决定是否抛出异常

  • 如果已连接:只需订阅目标

    如果断开连接:首先调用connect(),然后订阅目标

    正如我前面提到的,如果订阅不是发生在
    subscribedestinition(“/foo”)
    中,而是你只是构建了你的可观察链,我想你会更快乐。在某些情况下,您只需要调用
    connect()
    ,我只需要使用
    .do()