1

Let's say I have an arbitrary value in my code: var arbitraryValue = null;

There are multiple places in my code that can change this value. Can I create an EventStream which is based on the changes of the this value? In other words, if arbitraryValue is changed, the new value is sent to the subscribers as an EventStream?

Jarzka
  • 755
  • 7
  • 22

3 Answers3

2

Use a Bus instead of a plain value:

var arbitraryValueBus = Bacon.Bus()

Now you can set the value using Bus.push:

arbitraryValueBus.push(newValue)

And you can listen to changes of the value by subscribing to the Bus:

arbitraryValueBus.forEach(newValue => console.log(newValue))

Notice that using a simple Bus, your subscribers will not get the value that had been set before the forEach call. So, if you want to add a "current value", and have your callback called immediately with the current value, you should use a Property:

var b = Bacon.Bus()
var p = arbitraryValueBus.toProperty()
p.forEach() // to make sure it's updated before adding subscribers
b.push("first value")
p.subscribe(x => console.log(x))

==> outputs "first value"

Now your subscribers will get the current value immediately, if there is one.

raimohanska
  • 3,265
  • 17
  • 28
1

Thanks for your answers! Perhaps Bacon.js was not what I was looking for so I decided to make my own "Reactive Programming" library. It calculates new values immediately without the need to check the value with setTimeout.

var = createReactiveValue = function(initialValue) {
return {
    "observers": [], // Call these functions with a new value when it has been set
    "value":initialValue,
    "set": function(newValue) {
        this.value = newValue;

        this.observers.forEach(function(observer) {
            // Call observers asynchronously
            setTimeout(function() { observer(this.value) }, 0);
        })
    },
    "get": function() {
        return this.value;
    },
    "addObserver": function(observer) {
        this.observers.push(observer);
    }
};
};

// If any of the dependant values change, sets reactive value 'value' to the result of calling 'result'
var = makeReaction = function(value, dependencies, result) {
    // Start watching changes in dependencies
    dependencies.forEach(function(dependency) {
        dependency.addObserver(function(newValue) {
            var newResult = result(value, dependencies);
            value.set(newResult);
        });
    });
};


// When 'reactiveValue' is changed, calls the given 'result' function with the new value
var = watchReaction = function(reactiveValue, result) {
    // Start watching changes in reactive value
    reactiveValue.addObserver(function(newValue) {
        result(newValue);
    });
};

var a = createReactiveValue(2);
var b = createReactiveValue(1);
var c = createReactiveValue(null);

// We want c to depend on both a and b. If either a or b change, c should    automatically recalculate it's value
makeReaction(c, [a, b], function(c, [a, b]) {
    return a.get() + b.get();
});

// If c is changed, for whatever reason, log it
watchReaction(c, function(newC) {
    console.log("Reaction completed: " + a.get() + " + " + b.get() + " = " + c.get());
});

// Test it by resetting value a to random
setInterval(function()
{
    var newValue = Math.random();
    a.set(newValue); },
1000); // Logs the new result imm

EDIT: Now available as a library: https://github.com/Jarzka/ReaktioJS

Jarzka
  • 755
  • 7
  • 22
0

Checking if the value changes

In js checking if the value of your variable changes isn't that hard.

function checkValue() {
    var newValue = value;
    if (newValue != value) {
        // Value has changed
        // .... (Code that needs to be executed)
    }
}

From reading your question i've concluded that you constantly need to be checking if the value changes. To do this I suggest the following function:

function checkValue(interval) {
    var checkInterval = setInterval(function () {
        var newValue = value;
        if (newValue != value) {
            // Value has changed
            // .... (Code that needs to be executed)
        }
    }, interval); 
}

Calling this function somewhere in the beginning of your code will check if your value has changed every interval milliseconds. To stop this process all you need to do is clear the interval. Note i've put the interval inside of a variable to make clearing the interval possible.

Clearing the interval would be as easy as:

clearInterval(checkInterval);

Note: Please set the interval so that it checks every second or so. (1000 milliseconds). It's probably not needed to go lower than that and checking more often is just giving the browser unnecessary work.

I hope this answers your question!

  • I'm btw not familiar with bacon.js, so any code you need on "sending the value to the subscribers as an eventString" will have to come from someone else, again, I hope i've answered your question. – Jesse van der Pluijm Jul 03 '16 at 19:36