Search code examples
frpbacon.js

My Throttable EventStream implementation - is it redundant?


Subject: I have a stream (actually combined stream from Bacon.interval and buttons clicks EventStreams) wich fires ajax request and solve task of manual and automatic data refresh.

Problem: After manual events (buttons clicks) I need reset timer because two immediate updates looks ugly.

My solution: I've created my own Bacon.interval implementation where event polls can be reseted http://jsfiddle.net/cvvkxveq/1/:

    Bacon.dynInterval = function(time,resetter){
    if(!time) return Bacon.once(new Bacon.Error("Invalid args"));
    var ivId, lastTime = Date.now();
    return time < 1 ? Bacon.once(new Bacon.Error("Invalid time")) : Bacon.fromBinder(function(sink) {
      function setUpInterval(){
        if(ivId) clearInterval(ivId);
        ivId = setInterval(function(){
          var n = Date.now();
          var tdx = n - lastTime;
          lastTime = n;
          sink(new Bacon.Next(tdx));
        },time);
      }
      setUpInterval();
      if(resetter) resetter.onValue(setUpInterval);

      return function() {
        clearInterval(ivId);
        sink(new Bacon.End())
      }
    })
  }

Question: Is such behaivour can be done without custom event stream?

Update (thanks @raimohanska's answer) basing on @raimohanska's answer I've also converded my ouUiE event sream (manualTriggerE) to property with initial value to accomplish immediate updates starts.

var quotesService = Bacon.constant({url:"quotes.php"});
var onUiE = $("#next_stock, #prev_stock, #refresh_quotes").clickE().map(".currentTarget.id");
var onUiP = onUiE.toProperty("");
var periodicUpdateE = onUiP.flatMapLatest(function(){ return Bacon.interval(3000)});
var manualPlusPeriodicP = onUiP.toEventStream().merge(periodicUpdateE);
var quotesStream = quotesService.sampledBy(manualPlusPeriodicP).ajax();

Solution

  • If you have a stream manualTriggerE, you can add periodic updates that are reseted on each manual trigger like this:

    let periodicUpdateE = manualTriggerE.flatMapLatest(() => Bacon.interval(1000))
    let manualPlusPeriodicE = manualTrigger.merge(periodicUpdateE)
    

    The trick is flatMapLatest: it restarts the periodic updates whenever a manual trigger occurs.