使用Reactive编程重写事件发射器(信号量示例)

时间:2015-05-20 07:30:48

标签: javascript node.js reactive-programming rxjs bacon.js

我使用事件发射器作为同步原语。例如,我有一个类在Redis中询问信号量就像结构一样。如果设置了信号量,则会发出一个事件。代码列在下面:

var redis = require("redis"),
    async = require('async'),
    client = redis.createClient(),
    assert = require('assert'),
    EventEmitter = require('events').EventEmitter;
    util = require('util');
var isMaster = false,
    SEMAPHORE_ADDRESS = 'semaphore';
var SemaphoreAsker = function() {
  var self = this;
  var lifeCycle = function (next) {
    client.set([SEMAPHORE_ADDRESS, true, 'NX', 'EX', 5], function(err, val) {
      console.log('client');
      if(err !== null) { throw err; }
      if(val === 'OK') {
        self.emit('crown');
      } else {
        console.log('still a minion');
      }
    });
  };
  async.forever(
    function(next) {
      setTimeout(
        lifeCycle.bind(null, next),
        1000
      );
    }
  );
};
util.inherits(SemaphoreAsker,  EventEmitter);
(new SemaphoreAsker()).on('crown', function() {
  console.log('I`m master');
});

它有效,但看起来有点沉重。是否可以使用BaconJS(RxJS / whateverRPlibrary)重写示例?

3 个答案:

答案 0 :(得分:3)

以下内容适用于RXJS:

var callback = Rx.Observable.fromNodeCallback(client.set, client);

var source = Rx.Observable.interval(1000)
.selectMany(function() {
  return callback([SEMAPHORE_ADDRESS, true, 'NX', 'EX', 5]);
})
.filter(function(x) { return x === 'OK'; })
.take(1);


source.subscribe(function(x) {
  console.log("I am master");
});

如果您愿意另外添加rx-node模块,您还可以使用

保留事件发射器结构
var emitter = RxNode.toEventEmitter(source, 'crown');

emitter.on('crown', function(){});
emitter.on('error', function(){});
emitter.on('end', function(){});

答案 1 :(得分:2)

我使用基本Bacon.fromBinder为此创建自定义流。如果没有一个工作示例,这有点猜测,但希望这对您有所帮助。

var redis = require("redis"),
    client = redis.createClient(),
    assert = require('assert'),
    Bacon = require('bacon');

var SEMAPHORE_ADDRESS = 'semaphore';

var SemaphoreAsker = function() {
  return Bacon.fromBinder(function (sink) {
    var intervalId = setInterval(pollRedis, 1000)

    return function unsubscribe() {
      clearInterval(intervalId)
    }

    function pollRedis() {
      client.set([SEMAPHORE_ADDRESS, true, 'NX', 'EX', 5], function(err, val) {
        if(err !== null) { sink(new Bacon.Error(err)) }
        else if(val === 'OK') { sink(new Bacon.Next('crown'))
        else { assert.fail(); }
      }
    }
  })
}

SemaphoreAsker().take(1).onValue(function() {
  console.log("I am master")
})

答案 2 :(得分:2)

@paulpdanies答案,但用培根改写:

var source = Bacon.interval(1000).flatMap(function() {
    return Bacon.fromNodeCallback(
        client, 'set', [SEMAPHORE_ADDRESS, true, 'NX', 'EX', 1]
    );
})
.filter(function(x) { return x === 'OK'; })
.take(1);

source.onValue(function(x) {
    console.log(x);
});