Javascript 使用反应式编程重写事件发射器(信号量示例)
我将使用事件发射器作为同步原语。例如,我有一个类在Redis中请求类似信号量的结构。如果设置了信号量,它将发出一个事件。代码如下所示:Javascript 使用反应式编程重写事件发射器(信号量示例),javascript,node.js,reactive-programming,rxjs,bacon.js,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;
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)重写示例?我使用basic创建了一个自定义流。如果没有一个有效的例子,这只是一点猜测,但希望这对您有所帮助
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")
})
以下内容在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节点
模块,您还可以使用
var emitter = RxNode.toEventEmitter(source, 'crown');
emitter.on('crown', function(){});
emitter.on('error', function(){});
emitter.on('end', function(){});
@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);
});
谢谢你的回答!take(1)在这种情况下做什么?它会在第一个值之后停止流吗?现在,我明白了。有一个unsubscribe函数,它会在第一个值之后调用它。确切地说,我们只对一个“OK”值感兴趣。在第一个值之后,使用
Bacon.fromBinder
创建的流没有更多订户,因此调用了unsubscribe函数。Bacon负责取消订阅,通常您甚至不需要编写任何取消订阅逻辑(我在这里手动创建流,所以我也必须编写unsubscribe逻辑)。从内存管理的角度来看,主要的一点是要记住使用take(…)
,takeUntil(…)
等,以便流在不再需要其值时结束。特别重要的是,如果您使用的是Bacon.Bus
。您好,请看我的答案。它模仿了@paulpdanies的回答。你觉得怎么样?很酷的问题。今晚到家后,我会发布一个RxJs答案以供比较。我认为它比我发布的培根答案要短一些。是的,这和我要发布的内容差不多,除了:callback=Rx.Observable.fromNodeCallback(client.set,client)代码>而不是使用回调中的。为您处理错误。很好地调用@Brandon,我相应地更新了示例。这看起来不错,您可以使用Bacon.fromNodeCallback(客户端,'set',[…])
来避免显式绑定