Search code examples
javascriptfunctional-programmingfrpbacon.js

Is it possible to throttle the bacon action `repeatedly` somehow?


I am using bacon.js and have some situation where signal is emitted from two sources:

sourceA :: EventStream a
sourceB :: EventStream Bool

When sourceA is fired, it should trigger some action that runs repeatedly onto perpetuity, except when a signal is fired from sourceB. So syntactically it might look like this:

aAction = sourceA
    . repeatedly (200, [1,2,3])
    . until      (sourceB)

So I'm basically asking for an analogue to takeWhile or takeUntil combinators, but can't find such a function in the source or documentation. Any thoughts?

It'd be even better if there's a generic combinator

throttleWhen :: Bool -> EventStream a

or

throttleWhen' :: EventStream Bool -> EventStream a

that terminates any bacon event stream on some condition, how would I go about implementing such a thing?

Note, this solution below:

faAction = sourceA  . repeatedly (200, [1,2,3])
aAction  = faAction . takeUntil  (sourceB) 

throttles the derived stream aAction, but not the original.


Solution

  • If I understood correctly, you're looking for a combinator that ends a stream when a truthy value appears in another stream. You can use a.takeUntil(b.filter(Bacon._.id)) to end a stream when a truthy value appears on b. If b is a Property, the result will end immediately in case b holds a truthy value at start.

    You solution might look like this.

    aAction = sourceA
      .flatMap(function() { 
        return Bacon.repeatedly (200, [1,2,3]) 
          .takeUntil(sourceB.filter(Bacon._.id))
      })
    

    This one will start a new stream for each element of sourceA and terminate that when a truthy value appears sourceB.

    Or, you can a.takeWhile(b.not()) if b is a Property. Ends immediately if Property has a truthy value to start with.

    So, if sourceB is a Property holding true/false and you want to be emitting values only when it holds false, you can

    aAction = sourceA
      .flatMap(function() { 
        return Bacon.repeatedly (200, [1,2,3]) 
          .takeWhile(sourceB.not())
      })