从Observable上的subcribe获取返回值

时间:2016-10-23 01:41:46

标签: javascript reactive-programming rxjs observer-pattern rxjs5

使用RxJS 5.0.0-rc.1,我尝试通过使用Observer交换数据,以与how generators/iterators work类似的方式与Observableyield进行通信和.next()。目的是了解对.subscribe的调用返回的内容,并根据该内容修改/更新我的可观察流中的以下值。

我不完全确定这是否可能。但是,我发现你可以捕获.subscribe回调引发的异常。以下代码段打印出"Boom!"

var source = Observable.create((observer) => {
  try {
    observer.next(42);
  } catch (e) {
    // This will catch the Error
    // thrown on the subscriber
    console.log(e.message);
  }
  observer.complete();
});

source.subscribe(() => {
  throw new Error('Boom!');
});

那么,如果不是投掷,订户返回一个值呢? Observable有没有办法检索它?也许我正以错误的方式接近这一点。如果是这样,那么"反应性"在这种情况下做事的方式?

非常感谢。

修改

我提出的一种可能方法是在流中的每个项目上提供回调函数。类似的东西:

var source = Observable.create((observer) => {
  // This will print "{ success: true }"
  observer.next({ value: 42, reply: console.log });
  observer.complete();
});

source.subscribe(({ value, reply }) => {
  console.log('Got', value);
  return reply({ success: true });
});

还有其他想法吗?

编辑2

由于我原来的问题对我想要实现的目标产生了一些困惑,我将描述我的现实世界情景。我正在编写用于通过队列管理消息的模块的API(很像简化的,在内存中,AMQP-RPC机制),虽然RxJS非常合适。

它的工作方式与您期望的一样:Publisher将消息推送到队列,然后传递给Consumer。在术语中,Consumer可以回复Publisher,如果感兴趣,可以收听该回复。

在理想情况下,API看起来像这样:

Consumer().consume('some.pattern')
  .subscribe(function(msg) {
    // Do something with `msg`
    console.log(msg.foo);
    return { ok: true };
  });

Publisher().publish('some.pattern', { foo: 42 })
// (optional) `.subscribe()` to get reply from Consumer

该示例将打印42

回复Publisher的逻辑位于Consumer函数中。但实际响应是来自.subscribe() 回调的。这引出了我的原始问题:我应该如何从流的创建者那里获取返回的值?

Consumer#consume()视为:

/**
 * Returns an async handler that gets invoked every time
 * a new message matching the pattern of this consumer
 * arrives.
 */
function waitOnMessage(observer) {
  return function(msg) {
    observer.next(msg);
    // Conceptually, I'd like the returned
    // object from `.subscribe()` to be available
    // in this scope, somehow.
    // That would allow me to go like: 
    // `sendToQueue(pubQueue, response);`
  }
}

return Observable.create((observer) => {
  queue.consume(waitOnMessage(observer));
});

它更有意义吗?

1 个答案:

答案 0 :(得分:2)

发电机和可观测量之间确实存在相似之处。如您所见here,observables(异步值序列)是iterables的异步版本(值的同步序列)。

现在,生成器是一个返回Iterable的函数。但是,Rxjs Observable包含一个生成器 - 也就是生成器(通过调用subscribe执行/启动)和生成的异步值序列(通过传递Observer对象观察到的) 。 subscribe调用返回Disposable,允许您停止接收值(断开连接)。因此,虽然生成器和可观察对象是双重概念,但使用它们的API会有所不同。

默认情况下,您无法使用rxjs observable API进行双向通信。你可能可以通过在主题中构建自己的反向通道来做到这一点(注意你必须有一个初始值来启动循环)。

var backChannel = Rx.Subject();
backChannel.startWith(initialValue).concatMap(generateValue)
  .subscribe(function observer(value){
  // Do whatever
  // pass a value through the backChannel
  backChannel.next(someValue)
})
// generateValue is a function which takes a value from the back channel 
// and returns a promise with the next value to be consumed by the observer.

你可以考虑用以下内容包装:

function twoWayObsFactory (yield, initialValue) {
  var backChannel = Rx.BehaviorSubject(initialValue);
  var next = backChannel.next.bind(backChannel);
  return {
    subscribe : function (observer) {
      var disposable = backChannel.concatMap(yield)
        .subscribe(function(x) {
           observer(next, x);
        });
      return {
        dispose : function (){disposable.dispose(); backChannel.dispose();}
      }
    }
  }
}

// Note that the observer is now taking an additional parameter in its signature
// for instance
// observer = function (next, yieldedValue) {
//              doSomething(yieldedValue);
//              next(anotherValue);
//            }
// Note also that `next` is synchronous, as such you should avoir sequences
// of back-and-forth communication that is too long. If your `yield` function
// would be synchronous, you might run into stack overflow errors.
// All the same, the `next` function call should be the last line, so order of
// execution in your program is the same independently of the synchronicity of
// the `yield` function

否则,您描述的行为似乎是异步生成器的行为。我从来没有使用过这样的,但是因为这是一个未来版本的javascript的提议,我想你可以 已经开始尝试使用Babel(参见https://github.com/tc39/proposal-async-iteration)。

编辑

如果您正在寻找一种环回机制(不太通用的方法,但很适合您的用例,如果您想要做的事情很简单),expand运算符可以提供帮助。要了解其行为,请查看doc以及SO上的以下答案,以获取在具体情况下使用的示例:

基本上expand允许您向下游发出值并在生产者中同时反馈该值。