6
votes

Well the title kindof says what I need. Because in Javascript timeouts asynchronous I need to know when something becomes true. I don't want busyloop.

Came up with:

function do_when(predicate, action, timeout_step) {
    if (predicate()) {
        action();
    } else {
        setTimeout(do_when, timeout_step, predicate, action, timeout_step);
    }
}

Is it good Javascript or can I make better?

3
@predicate is function, action is also functionzaharpopov
The predicate is the condition when that has to be true before the action is called. ==> Looks sound to me.AxelEckenberger

3 Answers

0
votes

It's decent enough, if it's easy enough to read and it works just fine then it's generally good javascript.

Performance-wise, it's generally better to call the function whenever whatever is set to true happens. So in whatever function that executes to make predicate() return true, you could just call action() at the end. But I'm sure that's what you would have done if you could, right?

You could also look at using a callback, where you register a javascript function to a particular variable or function argument and when the function is run it executes whatever function was set to the callback variable.

6
votes

Depending on what the predicate is, you might be able to fit your problem into an implementation of the observer pattern. A while back I wrote a blog post about creating JavaScript objects with observable properties. It really depends on what the predicate is, but this might get you most of the way there with code like this:

var observable = createObservable({ propToWatch: false });
observable.observe('propToWatch', function (oldValue, newValue) { 
    alert('propToWatch has changed from ' + oldValue + ' to ' + newValue); 
});
observable.propToWatch(true); // alert pops

Of course, this might be overkill for your example. Since it's never listed out explicitly (n.b. I am not a very good blogger), here's the complete code needed to make this work:

var createMediator = function () {
    var events = {};
    return {
        subscribe: function (eventName, callback) {
            events[eventName] = events[eventName] || [];
            events[eventName].push(callback);
        },
        publish: function (eventName) {
            var i, callbacks = events[eventName], args;
            if (callbacks) {
                args = Array.prototype.slice.call(arguments, 1);
                for (i = 0; i < callbacks.length; i++) {
                    callbacks[i].apply(null, args);
                }
            }
        }
    };
};

var createObservable = function (properties) {
    var notifier = createMediator(), createObservableProperty, observable;
    createObservableProperty = function (propName, value) {
        return function (newValue) {
            var oldValue;
            if (typeof newValue !== 'undefined' &&
                value !== newValue) {
                oldValue = value;
                value = newValue;
                notifier.publish(propName, oldValue, value);
            }
            return value;
        };
    };
    observable = {
        register: function (propName, value) {
            this[propName] = createObservableProperty(propName, value);
            this.observableProperties.push(propName);
        },
        observe: function (propName, observer) {
            notifier.subscribe(propName, observer);
        },
        observableProperties: []
    };
    for (propName in properties) {
        observable.register(propName, properties[propName]);
    }
    return observable;
};

My observable objects make use internally of a small eventing framework (the createMediator function) I wrote once for a project. (Before realizing jQuery supported custom events. D'oh!) Again, this may or may not be overkill for your need, but I thought it was a fun hack. Enjoy!

-1
votes

if your predicate become true when a variable change, here is another solution:

say we want to log 'Big brother is watching you' when value of object a become 2.

function observable (value, condition, callback){
    this.value = value;
    this.condition = condition;
    this.callback = callback;
}

observable.prototype = {
    get value () {
        return this._value;
    },
    set value (value) {
        this._value = value;
        if (this.condition && this.callback && this.condition (value)) {
            this.callback (value);
        }
    }
};

condition = function (value) {
    console.log ('condition', value);
    return value === 2;
}

callback = function (value) {
    console.info ('Big Brother is watching you!');
}

var a = new observable (0, condition, callback);

console.log ('set value to 1');
a.value = 1;
console.log ('set value to 2');
a.value = 2;
console.log ('set value to 3');
a.value = 3;

you can try this exemple in firefox