试图使我自己的RxJs可观察

时间:2014-02-10 01:52:21

标签: node.js rxjs

我试图将现有的API转换为与RxJS一起使用...对于节点来说是相当新的,对RxJ来说是新手,所以请耐心等待。

我有一个现有的API(getNextMessage),它可以阻止(异步),或者当某个东西可用时,通过节点样式(错误,val)回调返回一个新项或错误。

所以它看起来像:

getNextMessage(nodeStyleCompletionCallback);

您可以将getNextMessage视为一个http请求,将来会在服务器响应时完成,但是一旦收到消息,您需要再次调用getNextMessage,以便不断从服务器获取新项目。

所以,为了使它成为一个可观察的集合,我必须让RxJs继续调用我的getNextMessage函数,直到订阅者被处置();

基本上,我正在尝试创建自己的RxJs可观察集合。

问题是:

  1. 我不知道怎么让subscriber.dispose()杀死async.forever
  2. 我可能不应该首先使用async.forever
  3. 我不确定我是否应该完成'对于每条消息 - 不应该在序列的末尾
  4. 我想最终删除使用fromNodeCallback的必要性,以获得第一类RxJS可观察
  5. 显然我有点困惑。
  6. 非常乐意帮助,谢谢!

    这是我现有的代码:

    var Rx = require('rx');
    var port = require('../lib/port');
    var async = require('async');
    
    function observableReceive(portName)
    {
        var observerCallback;
        var listenPort = new port(portName);
        var disposed = false;
    
        var asyncReceive = function(asyncCallback)
        {
            listenPort.getNextMessage(
                function(error, json)
                {
                    observerCallback(error, json);
    
                    if (!disposed)
                        setImmediate(asyncCallback);
                }
            );
        }
    
        return function(outerCallback)
        {
            observerCallback = outerCallback;
            async.forever(asyncReceive);
        }
    }
    
    var receive = Rx.Observable.fromNodeCallback(observableReceive('rxtest'));
    var source = receive();
    
    var subscription = source.forEach(
        function (json)
        {
            console.log('receive completed: ' + JSON.stringify(json));
        },
        function (error) {
            console.log("receive failed: " + error.toString());
        },
        function () {
            console.log('Completed');
            subscription.dispose();
        }
    );
    

2 个答案:

答案 0 :(得分:14)

所以这可能就是我要做的事。

var Rx = require('Rx');

// This is just for kicks. You have your own getNextMessage to use. ;)
var getNextMessage = (function(){

  var i = 1;

  return function (callback) {
    setTimeout(function () {
      if (i > 10) {
        callback("lawdy lawd it's ova' ten, ya'll.");
      } else {
        callback(undefined, i++);
      }
    }, 5);
  };

}());

// This just makes an observable version of getNextMessage.
var nextMessageAsObservable = Rx.Observable.create(function (o) {
  getNextMessage(function (err, val) {
    if (err) {
      o.onError(err);
    } else {
      o.onNext(val);
      o.onCompleted(); 
    }
  });
});

// This repeats the call to getNextMessage as many times (11) as you want.
// "take" will cancel the subscription after receiving 11 items.
nextMessageAsObservable
  .repeat()
  .take(11)
  .subscribe(
    function (x)   { console.log('next', x);    },
    function (err) { console.log('error', err); },
    function ()    { console.log('done');       }
  );

答案 1 :(得分:5)

我意识到这已经超过一年了,但我认为更好的解决方案是使用递归调度代替:

Rx.Observable.forever = function(next, scheduler) {
  scheduler = scheduler || Rx.Scheduler.default,
  //Internally wrap the the callback into an observable
  next = Rx.Observable.fromNodeCallback(next);    

  return Rx.Observable.create(function(observer) {
    var disposable = new Rx.SingleAssignmentDisposable(),
        hasState = false;
    disposable.setDisposable(scheduler.scheduleRecursiveWithState(null, 
      function(state, self) { 
        hasState && observer.onNext(state);
        hasState = false;  
        next().subscribe(function(x){
          hasState = true;
          self(x);
        }, observer.onError.bind(observer));

      }));

    return disposable;

  });

};

这里的想法是,您可以在上一个项目完成后安排新项目。您调用next()来调用传入的方法,当它返回一个值时,您可以安排下一个项目进行调用。

然后您可以这样使用它:

Rx.Observable.forever(getNextMessage)
.take(11)
.subscribe(function(message) {
 console.log(message);
});

查看工作示例here