baconjs / bacon.js

Functional reactive programming library for TypeScript and JavaScript

Home Page:https://baconjs.github.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

To "streamify" a map of callbacks

junjchen opened this issue · comments

Hi guys,

I was doing a facade on a legacy API where a map of callback is passed in as an arg like:

const myStupidListeners = {
    aHappened: e => {},
    bHappened: e => {},
    cHappened: e => {}
}

invokeLegacyAPI("start", myStupidListeners)

I was trying to wrap this API to multiple event streams using bacon, so for each xHappened callback, an event stream shall be created.

But however I just can't spin my head around how to "streamify" those callbacks using factory functions provided by Bacon, at best I'm thinking of kicking start a Bus for each callbacks and pushing events to that bus in those callbacks.

Am I missing somehing form the doc and is there a better way to do this?

Probably a Bus is the easiest solution. There are other options but since you have three callbacks you want to pass simultaneously it's a bit trickier.

const onA = new Bacon.Bus();
const onB = new Bacon.Bus();
const onC = new Bacon.Bus();

const myStupidListeners = {
    aHappened: ev => onA.push(ev),
    bHappened: ev => onB.push(ev),
    cHappened: ev => onC.push(ev),
};

invokeLegacyAPI("start", myStupidListeners);

If you need help with the finer points, like unsubscribing or signalling the stream done event you'll have to provide some more details on the legacy API.

Optionally you can

allEvents = B.fromBinder(function(sink) { invokeLegacyAPI({a: sink, b: sink, c: sink}) })

This ways you'll get all events into one stream. Then you need to split it into three by applying different filters. Note that you could also can tag your data like

allEvents = B.fromBinder(function(sink) { invokeLegacyAPI({
  a: function(a) { sink ({a: a}) }, 
  b: function(b) { sink ({b: b}) }, 
  c: function(b) { sink ({c: c}) }
})})

So that you allEvents stream will output stuff like

{a: "value from event a" }
{c: "something else from c"}

The Bus approach seems more approachable to me.

@philipnilsson @raimohanska Thank you for your great input on the topic.

The only concern to exploit Bacon.Bus from me is that it enables user to be a little over-powered to push events to the bus.

I have not thought of using fromBinder before and it seems to be a decent approach as well.

Another solution pops into my mind just now was to use EventEmitter and Bacon.fromEvent, something like

const emitter = new EventEmitter()
const myStupidListeners = {
    aHappened: e => emitter.emit('a', e),
    bHappened: e => emitter.emit('b', e),
    cHappened: e => emitter.emit('c', e)
}
// then from events
const onA = Bacon.fromEvent(emitter, 'a');
const onB = Bacon.fromEvent(emitter, 'b');
const onC = Bacon.fromEvent(emitter, 'c');

Haven't tried out yet but looks as well approachable.

@junjchen Did this solution work out for you? Can we close this issue?