RxJs avoid external state but still access previous values

妖精的绣舞 提交于 2019-12-07 08:59:46

问题


I'm using RxJs to listen to a amqp queu (not really relevant).

I have a function createConnection that returns an Observable that emits the new connection object. Once I have a connection, I want to send messages through it every 1000ms and after 10 messages I want to close the connection.

I'm trying to avoid external state, but if I don't store the connection in an external variable, how can I close it? See I begin with the connection, then flatMap and push messages, so after a few chains I no longer have the connection object.

This is no my flow but imagine something like this:

createConnection()
  .flatMap(connection => connection.createChannel())
  .flatMap(channel => channel.send(message))
  .do(console.log)
  .subscribe(connection => connection.close()) <--- obviously connection isn't here

Now I understand that it's stupid to do that, but now how do I access the connection? I could of course begin with var connection = createConnection()

and later on somehow join that. But how do I do this? I don't even know how to ask this question properly. Bottomline, what I have is an observable, that emits a connection, after the connection is opened I want an observable that emits messages every 1000ms (with a take(10)), then close the connection


回答1:


The direct answer to your question is "you can carry it through each step". For example, you can replace this line

.flatMap(connection => connection.createChannel())

with this one:

.flatMap(connection => ({ connection: connection, channel: connection.createChannel() }))

and retain access to the connection all the way down.

But there's another way to do what you want to do. Let's assume your createConnection and createChannel functions look something like this:

function createConnection() {
  return Rx.Observable.create(observer => {
    console.log('creating connection');
    const connection = {
      createChannel: () => createChannel(),
      close: () => console.log('disposing connection')
    };

    observer.onNext(connection);

    return Rx.Disposable.create(() => connection.close());
  });
}

function createChannel() {
  return Rx.Observable.create(observer => {
    const channel = {
      send: x => console.log('sending message: ' + x)
    };

    observer.onNext(channel);

    // assuming no cleanup here, don't need to return disposable
  });
}

createConnection (and createChannel, but we'll focus on the former) returns a cold observable; each subscriber will get their own connection stream containing a single connection, and when that subscription expires, the dispose logic will be called automatically.

This allows you to do something like this:

const subscription = createConnection()
  .flatMap(connection => connection.createChannel())
  .flatMap(channel => Rx.Observable.interval(1000).map(i => ({ channel: channel, data: i })))
  .take(10)
  .subscribe(x => x.channel.send(x.data))
;

You don't actually have to dispose the subscription for cleanup to occur; after take(10) is satisfied, the whole chain will finish and cleanup will be triggered. The only reason you'd need to call dispose on the subscription explicitly is if you wanted to tear things down before the 10 1000ms intervals were up.

Note that this solution also contains an instance of the direct answer to your question: we cart the channel down the line so we can use it in the onNext lambda passed to the subscribe call (which is customarily where such code would appear).

Here's the whole thing working: https://jsbin.com/korihe/3/edit?js,console,output




回答2:


This code gave me a error because flatmap wait for a observable<(T)> and ({ connection: connection, channel: connection.createChannel() }) it's a Object.

.flatMap(connection => ({ connection: connection, channel: connection.createChannel() }))

instead you can use the combineLatest operator

.flatMap(connection => Observable.combineLatest( Observable.of(connection), connection.createChannel(), (connection, channel) => { ... code .... });



来源:https://stackoverflow.com/questions/36612519/rxjs-avoid-external-state-but-still-access-previous-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!