Search code examples
javascriptreactive-programmingbacon.js

Beginner problems with reactive programming


I'm using Kefir.js for reactive programming, but I have some troubles. I have a device with N sensors (temperature, pressure, time, ...) and I think it would be great idea if I represent sensors as streams. So I end up with this code:

function temperatureSensor(pin) {
  let stream = Kefir.emitter()

  if(pin > 12) {
    stream.error(new Error(`Board has no pin ${pin}.`))
  }

  setInterval(() => {
    stream.emit(readTemperature(pin))
  }, 500)

  return stream
}

Kefir.zip([
  temperatureSensor(1),
  temperatureSensor(42) // Invalid pin, should call .error
]).onValue((state) => {
  // do something with sensor values
}).onError(() => {
  console.error('An error occurred!')
})

There is few problems with this code:

  1. .onError will never be called (.onError is attached after .error is called). Maybe use property instead of stream, but I don't know how...
  2. .zip is not a ideal function, I need something like that:

Synchronize sensors, call .onValue, then .onValue every time when sensor value change

a:    ----20------------21--------------
b:    -------25--------------------24---
ab:   --------•----------•----------•---
       [20, 25]   [21, 25]   [21, 24]

Thank you for any advice.


Solution

  • There is built-in functionality for reading a value from a function, Kefir.fromPoll.

    function temperatureSensor(pin) {
      return Kefir.fromPoll(500, function() {
        return readTemperature(pin)
      }
    }
    

    For the error handling, I would just use standard javascript error functionality, eg. throwing an error. You can know wether the pin is correct when creating the stream, so no need for reactive programming.

    The combinator function you're looking for is combine. The complete example would be:

    function temperatureSensor(pin) {    
      if(pin > 12) {
        throw new Error(`Board has no pin ${pin}.`)
      }
    
      return Kefir.fromPoll(500, function() {
        return readTemperature(pin)
      }
    }
    
    Kefir.combine([
      temperatureSensor(1),
      temperatureSensor(42)
    ]).onValue((state) => {
      // do something with sensor values
    }).onError(() => {
      console.error('An error occurred!')
    })