[javascript] How can I make a program wait for a variable change in javascript?

I want to force a JavaScript program to wait in some particular points of its execution until a variable has changed. Is there a way to do it? I have already found an extension that is called "narrative JavaScript" that force the program to wait until an event to happen. Is there a way to create a new event, a "variable change event" for example that behaves like onclick event..

This question is related to javascript variables wait

The answer is


JavaScript interpreters are single threaded, so a variable can never change, when the code is waiting in some other code that does not change the variable.

In my opinion it would be the best solution to wrap the variable in some kind of object that has a getter and setter function. You can then register a callback function in the object that is called when the setter function of the object is called. You can then use the getter function in the callback to retrieve the current value:

function Wrapper(callback) {
    var value;
    this.set = function(v) {
        value = v;
        callback(this);
    }
    this.get = function() {
        return value;
    }  
}

This could be easily used like this:

<html>
<head>
<script type="text/javascript" src="wrapper.js"></script>
<script type="text/javascript">
function callback(wrapper) {
    alert("Value is now: " + wrapper.get());
}

wrapper = new Wrapper(callback);
</script>
</head>
<body>
    <input type="text" onchange="wrapper.set(this.value)"/>
</body>
</html>

You can use properties:

Object.defineProperty MDN documentation

Example:

function def(varName, onChange) {
    var _value;

    Object.defineProperty(this, varName, {
        get: function() {
            return _value;
        },
        set: function(value) {
            if (onChange)
                onChange(_value, value);
            _value = value;
        }
    });

    return this[varName];
}

def('myVar', function (oldValue, newValue) {
    alert('Old value: ' + oldValue + '\nNew value: ' + newValue);
});

myVar = 1; // alert: Old value: undefined | New value: 1
myVar = 2; // alert: Old value: 1 | New value: 2

Edit 2018: Please look into Object getters and setters and Proxies. Old answer below:


a quick and easy solution goes like this:

var something=999;
var something_cachedValue=something;

function doStuff() {
    if(something===something_cachedValue) {//we want it to match
        setTimeout(doStuff, 50);//wait 50 millisecnds then recheck
        return;
    }
    something_cachedValue=something;
    //real action
}

doStuff();

The question was posted long time ago, many answers pool the target periodically and produces unnecessary waste of resources if the target is unchanged. In addition, most answers do not block the program while waiting for changes as required by the original post.

We can now apply a solution that is purely event-driven.

The solution uses onClick event to deliver event triggered by value change.

The solution can be run on modern browsers that support Promise and async/await. If you are using Node.js, consider EventEmitter as a better solution.

_x000D_
_x000D_
<!-- This div is the trick.  -->_x000D_
<div id="trick" onclick="onTrickClick()" />_x000D_
_x000D_
<!-- Someone else change the value you monitored. In this case, the person will click this button. -->_x000D_
<button onclick="changeValue()">Change value</button>_x000D_
_x000D_
<script>_x000D_
_x000D_
    // targetObj.x is the value you want to monitor._x000D_
    const targetObj = {_x000D_
        _x: 0,_x000D_
        get x() {_x000D_
            return this._x;_x000D_
        },_x000D_
        set x(value) {_x000D_
            this._x = value;_x000D_
            // The following line tells your code targetObj.x has been changed._x000D_
            document.getElementById('trick').click();_x000D_
        }_x000D_
    };_x000D_
_x000D_
    // Someone else click the button above and change targetObj.x._x000D_
    function changeValue() {_x000D_
        targetObj.x = targetObj.x + 1;_x000D_
    }_x000D_
_x000D_
    // This is called by the trick div. We fill the details later._x000D_
    let onTrickClick = function () { };_x000D_
_x000D_
    // Use Promise to help you "wait". This function is called in your code._x000D_
    function waitForChange() {_x000D_
        return new Promise(resolve => {_x000D_
            onTrickClick = function () {_x000D_
                resolve();_x000D_
            }_x000D_
        });_x000D_
    }_x000D_
_x000D_
    // Your main code (must be in an async function)._x000D_
    (async () => {_x000D_
        while (true) { // The loop is not for pooling. It receives the change event passively._x000D_
            await waitForChange(); // Wait until targetObj.x has been changed._x000D_
            alert(targetObj.x); // Show the dialog only when targetObj.x is changed._x000D_
            await new Promise(resolve => setTimeout(resolve, 0)); // Making the dialog to show properly. You will not need this line in your code._x000D_
        }_x000D_
    })();_x000D_
_x000D_
</script>
_x000D_
_x000D_
_x000D_


I would recommend a wrapper that will handle value being changed. For example you can have JavaScript function, like this:

?function Variable(initVal, onChange)
{
    this.val = initVal;          //Value to be stored in this object
    this.onChange = onChange;    //OnChange handler

    //This method returns stored value
    this.GetValue = function()  
    {
        return this.val;
    }

    //This method changes the value and calls the given handler       
    this.SetValue = function(value)
    {
        this.val = value;
        this.onChange();
    }


}

And then you can make an object out of it that will hold value that you want to monitor, and also a function that will be called when the value gets changed. For example, if you want to be alerted when the value changes, and initial value is 10, you would write code like this:

var myVar = new Variable(10, function(){alert("Value changed!");});

Handler function(){alert("Value changed!");} will be called (if you look at the code) when SetValue() is called.

You can get value like so:

alert(myVar.GetValue());

You can set value like so:

myVar.SetValue(12);

And immediately after, an alert will be shown on the screen. See how it works: http://jsfiddle.net/cDJsB/


No you would have to create your own solution. Like using the Observer design pattern or something.

If you have no control over the variable or who is using it, I'm afraid you're doomed. EDIT: Or use Skilldrick's solution!

Mike


What worked for me (I looked all over the place and ended up using someone's jsfiddler / very slightly modifying it - worked nicely) was to set that variable to an object with a getter and setter, and the setter triggers the function that is waiting for variable change.

var myVariableImWaitingOn = function (methodNameToTriggerWhenChanged){
    triggerVar = this;
    triggerVar.val = '';
    triggerVar.onChange = methodNameToTriggerWhenChanged;
    this.SetValue(value){
        if (value != 'undefined' && value != ''){
            triggerVar.val = value; //modify this according to what you're passing in -
            //like a loop if an array that's only available for a short time, etc
            triggerVar.onChange(); //could also pass the val to the waiting function here
            //or the waiting function can just call myVariableImWaitingOn.GetValue()
        }
    };
    this.GetValue(){
        return triggerVar.val();
    };
 };

Super dated, but certainly good ways to accomodate this. Just wrote this up for a project and figured I'd share. Similar to some of the others, varied in style.

var ObjectListener = function(prop, value) {

  if (value === undefined) value = null;

  var obj = {};    
  obj.internal = value;
  obj.watcher = (function(x) {});
  obj.emit = function(fn) {
    obj.watch = fn;
  };

  var setter = {};
  setter.enumerable = true;
  setter.configurable = true;
  setter.set = function(x) {
    obj.internal = x;
    obj.watcher(x);
  };

  var getter = {};
  getter.enumerable = true;
  getter.configurable = true;
  getter.get = function() {
    return obj.internal;
  };

  return (obj,
    Object.defineProperty(obj, prop, setter),
    Object.defineProperty(obj, prop, getter),
    obj.emit, obj);

};


user._licenseXYZ = ObjectListener(testProp);
user._licenseXYZ.emit(testLog);

function testLog() {
  return function() {
    return console.log([
        'user._licenseXYZ.testProp was updated to ', value
    ].join('');
  };
}


user._licenseXYZ.testProp = 123;

JavaScript is one of the worst program\scripting language ever!

"Wait" seems to be impossible in JavaScript! (Yes, like in the real life, sometimes waiting is the best option!)

I tried "while" loop and "Recursion" (a function calls itself repeatedly until ...), but JavaScript refuses to work anyway! (This is unbelievable, but anyway, see the codes below:)

while loop:

<!DOCTYPE html>

<script>

var Continue = "no";
setTimeout(function(){Continue = "yes";}, 5000);    //after 5 seconds, "Continue" is changed to "yes"

while(Continue === 'no'){};    //"while" loop will stop when "Continue" is changed to "yes" 5 seconds later

    //the problem here is that "while" loop prevents the "setTimeout()" to change "Continue" to "yes" 5 seconds later
    //worse, the "while" loop will freeze the entire browser for a brief time until you click the "stop" script execution button

</script>

Recursion:

<!DOCTYPE html>

1234

<script>

function Wait_If(v,c){
if (window[v] === c){Wait_If(v,c)};
};

Continue_Code = "no"
setTimeout(function(){Continue_Code = "yes";}, 5000);    //after 5 seconds, "Continue_Code" is changed to "yes"

Wait_If('Continue_Code', 'no');

    //the problem here, the javascript console trows the "too much recursion" error, because "Wait_If()" function calls itself repeatedly!

document.write('<br>5678');     //this line will not be executed because of the "too much recursion" error above!

</script>

Alternatively, you can make a function that executes tasks based on the value of its "Static" variables, example below:

enter image description here

<!DOCTYPE html>

<div id="Time_Box"> Time </div>

<button type="button" onclick='Update_Time("on")'>Update Time On</button>
<button type="button" onclick='Update_Time("off")'>Update Time Off</button>

<script>

var Update_Time = (function () {     //_____________________________________________________________

var Static = [];             //"var" declares "Static" variable as static object in this function

    return function (Option) {

    var Local = [];           //"var" declares "Local" variable as local object in this function

        if (typeof Option === 'string'){Static.Update = Option};

        if (Static.Update === "on"){
        document.getElementById("Time_Box").innerText = Date();

        setTimeout(function(){Update_Time()}, 1000);    //update every 1 seconds
        };

    };

})();  

Update_Time('on');    //turns on time update

</script>

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to variables

When to create variables (memory management) How to print a Groovy variable in Jenkins? What does ${} (dollar sign and curly braces) mean in a string in Javascript? How to access global variables How to initialize a variable of date type in java? How to define a variable in a Dockerfile? Why does foo = filter(...) return a <filter object>, not a list? How can I pass variable to ansible playbook in the command line? How do I use this JavaScript variable in HTML? Static vs class functions/variables in Swift classes?

Examples related to wait

How to make the script wait/sleep in a simple way in unity How do I make a delay in Java? Wait some seconds without blocking UI execution Protractor : How to wait for page complete after click a button? How to wait until an element is present in Selenium? Javascript sleep/delay/wait function How to wait till the response comes from the $http request, in angularjs? How to add a "sleep" or "wait" to my Lua Script? Concept behind putting wait(),notify() methods in Object class How can I wait for 10 second without locking application UI in android