2

I am taking small steps in FRP land with BaconJS. I have the following code:

# This will eventually get resolved with some value
dfd = Promise.defer()
promised = Bacon.fromPromise dfd.promise

# Values are occasionally being pushed in here
bus = new Bacon.Bus

# 1. attempt
bus.combine promised, (fromBus, fromPromise) ->
   # This is never invoked

# 2. attempt
Bacon.combineAsArray( bus, promised ).onValues (fromBus, fromPromise) ->
   # This is invoked only once for the latest value from the bus

# 3. attempt
promised.sampledBy(bus).onValue (fromPromise, fromBus) ->
   # No invoke here at all

# These are called asynchronously during application lifespan
bus.push obj1
dfd.resolve value
bus.push obj2
bus.push obj3

I want to update every delivered object through Bus with the value from the promise object including those, that were pushed there before promise was resolved. I could do something this:

bus.onValue (fromBus) ->
    promise.then (fromPromise) ->
        ...

Yes, that works, but I just don't like it and I want to see if FRP can solve it more elegantly. Do you have any hints how do it pure FRP way, please ?

Update

I was thinking about some other approaches. Here is some background what's going on actually...

# Simple function that creates some object instance (if it haven't been created yet ) and returns it
getObject = (name) ->
   unless obj = list[name]
     obj = new Obj()
     bus.push obj

For every object added to the cache I need to set some property to value that comes from the Promise. Basically I could do it like this:

obj = new Obj()
dfd.promise.then (resolvedValue) ->
    obj.someProperty = resolvedValue

This is perfectly viable solution without FRP, however as you may know, every .then call is forced to be asynchronous. It pays it's price with lowered performance. I would like to overcome this. If I understand it correctly, using FRP it would call .then just once and then provide static value. Question remains how to do it...

Solved

Check out fiddle. In short, it can look like this:

bus.flatMap(
    Bacon.combineAsArray.bind Bacon, promised
).onValue ([fromPromise, fromBus]) ->
    fromBus.specialProperty = fromPromise
FredyC
  • 3,999
  • 4
  • 30
  • 38
  • 1
    Nice to see you making progress! Just a side note - a promise is a one time thing that only resolves once, thus a `Bacon.fromPromise` creates a stream that only gets one value, or an error. Why are you using the deferred here? – Benjamin Gruenbaum May 14 '14 at 22:07
  • @BenjaminGruenbaum Deferred is just for sake of example so you can see I am resolving it somewhere in the middle. I thought that using `fromPromise` will watch for promise resolution and than keep to value and provide it for any consumers. Isn't that correct ? Would it help to convert it `.toProperty` ? – FredyC May 15 '14 at 04:56

1 Answers1

0

Looks like you're looking for flatMap (again):

busValuesWithPromise = bus.flatMap (busValue) ->
    Bacon.combineAsArray(promised, busValue)
busValuesWithPromise.onValues (fromPromise, fromBus) ->
    # every bus update, together with the promise value
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Well, this looks totally same as my solution without FRP :) Guess that FRP is not that magical. I would rather see some solution with less closure and having both values in one function call as you can seen in my three failed attempts. – FredyC May 15 '14 at 04:41
  • Well, the point is that it does return a stream now - i might not have emphasized this enough. – Bergi May 15 '14 at 05:10
  • Hmm, I see, but that's just sugar. Closures will be still in there :( – FredyC May 15 '14 at 05:16
  • Well, FRP is always "just sugar" :-) However, to sugar the closure away, I've now found what I think is the proper function for this: [`combineAsArray`](https://github.com/baconjs/bacon.js#bacon-combineasarray) – Bergi May 15 '14 at 05:21
  • Thanks @Bergi ! This definitely looks somewhat nicer, although I don't like much about that creating new stream and then having to use `onValues`, but I guess that's just part of FRP that I have to accept :) I made small [fiddle](http://jsfiddle.net/k48qH/) with working solution and polished it little bit. – FredyC May 15 '14 at 19:43
  • Oh, nice! I thought about shortening it like that, but it seemed a little too complicated - good if you're fine with it. The more explicit snippet looks easier to understand. – Bergi May 15 '14 at 19:54