Development

SpeedQuizzing software development. Technologies, ideas, ethos.

Real world reactive programming example with KefirJS

Real world reactive programming example with KefirJS

Reactive programming libraries like RxJS, BaconJS and KefirJS have been of interest to me for sometime now. Our software, SpeedQuizzing, being that it is a realtime game, accepting incoming data from multiple connected mobile devices, is all about handling asynchronous events which is what reactive programming is also very much about.

The main concept behind reactive programming is the Observable. An Observable being like an Array/Collection, but received over time. So like a continuous stream of data that you can process, in realtime, as soon as it starts arriving.

Future gazing, it is nice to think that in a build to come that the whole SpeedQuizzing system could be rebuilt in this way. I’m sure it would fantastic.. but that is a little way off. Where I am at currently is simply taking first steps into learning/trying out these libraries, to see how they fair and see if I can get my head around it!

Approachable KefirJS

For this first try, I gave KefirJS a spin. There is something very approachable about this library that made me want to jump straight in, more so than with RX or Bacon. Also, I like small libraries (53k).

Building a number stepper

Starter examples of reactive programming on the web are all too often the same things. Button click counters, drag and drops and autocomplete/typeaheads. Occasionally this makes you wonder if these are all it is useful for, but I’m sure this isn’t actually the case.

For this demo (and my first play with Kefir), I have built a number stepper. I wanted to create something practical that I will eventually use in our software and something that has a moderate amount of complexity. And as well, because a big part of these libraries are functions for you to use in place of timing utilities like setTimeout and setInterval, which when used to achieve functionality such as buttons that respond to a press-and-hold, this can get very messy, very quickly.

Anyway. Here is my KefirJS working number stepper on jsFiddle.

http://jsfiddle.net/johnsq/j1hwrfjf/4/

And here is the code (a mere 22 lines, without the comments).


// Get dom elements.

var score_display = document.getElementById("score_display");
var down_button = Kefir.fromEvents(document.querySelector('#score_down'), 'mousedown');
var up_button = Kefir.fromEvents(document.querySelector('#score_up'), 'mousedown');

// Merge down and up button mousedowns into a stream.

var button_mousedowns = Kefir.merge([down_button, up_button]).onValue(function(e) {

// 'single' ensures a press is acknowledged on a short click (less that 100mm).

   var single = Kefir.constant(e.target.id);

// 'burst', (an event fired every 100mm) starts when either of the buttons is held for 100mm+.

  var burst = Kefir.interval(100, e.target.id);

// single and burst and merged into a single stream.

   var merged = Kefir.merge([single, burst])

// this function cancels the stream when a mouseup event occurs.

		.takeUntilBy(Kefir.fromEvents(document, 'mouseup'));	

// filter the 'down' button events. Update the text input, then stop the stream when the min amount is reached.

   	var decrement = merged.takeWhile(function(x) { return x == "score_down";  })
    			.takeWhile(function(){return parseInt(score_display.value) > -20})
   			.onValue(function(x){
      			score_display.value = parseInt(score_display.value)-1;
  			}); 
// filter the 'up' button events. Update the text input, then stop the stream when the max amount is reached.  

       var increment = merged.takeWhile(function(x) {  return x == "score_up";  })
    			.takeWhile(function(){return parseInt(score_display.value) < 20})
   			.onValue(function(x){
      			score_display.value = parseInt(score_display.value)+1;
  			});

// log out whenever the stream has ended.

        merged.onEnd(function() {
  			console.log('stream ended');
			});
 });

Conclusion

Thinking of your code as streams does make a lot of sense once you get the hang of it. I will definitely be revisiting KefirJS soon in the future.

I hope this helps anyone starting out with reactive programming. Follow me on Twitter @johnleachyork.