Опубликовать/подписаться

Я пытаюсь реализовать шаблон публикации/подписки в Node, но без Redis. Функциональность должна быть одинаковой; вы можете опубликовать канал, подписаться на канал и слушать данные, если вы подписались; вот функции Redis:

pub.publish('channel1', myData1, function (err, data) {     
});


sub.subscribe('channel1', function (err, data) {
});


sub.on("message", function (channel, data) {
    //Now you are easily listening to data
});

Я пробовал следующее, что может быть не очень хорошим способом (я просто показываю свою попытку!); У меня есть собственный объект канала, в котором я сохраняю каналы и функции, которые необходимо запускать, когда мы публикуем новые данные на определенном канале; так что, как вы видите, я подписываюсь на функции каналов; но я не знаю, могу ли я как-то прослушивать данные, как это делает Redis sub.on("message",function(){...! Не могли бы вы помочь мне, если я могу сделать это так же, как Redis, но с eventEmitter или...

var events = require('events');
var emitter = new events.EventEmitter;
var channels = {};
//channels ={"channelA": ["func1", "func2"], "channelB": []}

//publish data to a channel and emits all of the functions which are registered for listening to the channel
function publish(channel, data, callback) {
    if (channels[channel] && channels[channel].length > 0) {
        for (var i = 0; i < channels[channel].length; i++) {
            emitter.emit(channels[channel][i], data);
        }
    }
    callback();

}

//subscribe a function to a channel
function subscribe(channel, FuncName, next) {
    if (!channels[channel]) {
        channels[channel] = [];
    }
    channels[channel].push(FuncName);
    next();
}

//Subscribe a callback function from a channel
function unsubscribe(channel, FuncName) {
    if (channels[channel]) {
        var indx = channels[channel].indexOf(FuncName);
        if (indx != -1) {
            channels[channel].splice(indx, 1);
        }
    }
}

person user385729    schedule 05.02.2015    source источник


Ответы (1)


Вы можете использовать EventEmitter для каждого канала. Кроме того, вы, вероятно, захотите сохранить ссылки на обратные вызовы, а не на строки имен функций.

var events = require('events');
var channels = {};

//publish data to a channel and emits all of the functions which are registered for listening to the channel
function publish(channel, data, callback) {
  if (channels[channel]) {
    channels[channel].emit('message', channel, data);
  }
  callback();
}

//subscribe a function to a channel
function subscribe(channel, fn, next) {
  if (!channels[channel]) {
    channels[channel] = new events.EventEmitter();
  }
  channels[channel].addListener('message', fn);
  next();
}

//unsubscribe a callback function from a channel
function unsubscribe(channel, fn) {
  if (channels[channel]) {
    channels[channel].removeListener('message', fn);
  }
}
person Ben    schedule 05.02.2015
comment
Большое спасибо! Я просто не понимаю, channels[channel].emit('message', channel, data); почему ты пропускаешь channel в этой строке? Итак, для подписки мне нужно передать ссылку на мой обратный вызов, и когда мы публикуем на канал, на который кто-то подписан, мы испускаем эту функцию обратного вызова, которая предоставляется при подписке, верно? - person user385729; 06.02.2015
comment
Я включил channel, потому что в вашем примере channel был одним из параметров обратного вызова (sub.on("message", function (channel, data) {...})). В этом нет необходимости. - person Ben; 06.02.2015
comment
EventEmitter отслеживает обратные вызовы для вас. Итак, все, что вам нужно сделать, это сказать EventEmitter, чтобы он вызывал обратный вызов, когда кто-то испускает message. Другой способ приблизиться к этому — использовать одно EventEmitter и пространство имен для событий. например имена событий могут быть чем-то вроде channel + ':message'. - person Ben; 06.02.2015