Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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..

like image 465
Thanasis Petsas Avatar asked Sep 03 '10 12:09

Thanasis Petsas


People also ask

How do you wait for something in JavaScript?

The standard way of creating a delay in JavaScript is to use its setTimeout method. For example: console. log("Hello"); setTimeout(() => { console.

Does JavaScript wait for response?

It queues the events in action and perform them in order. But in some case, Javascript behaves as asynchronous, such as in AJAX or Axios calls. It makes a call to the API but does not wait for the API to return result, and progresses with the next queued event.

Does JavaScript wait for function to finish before continuing?

JavaScript code execution is asynchronous by default, which means that JavaScript won't wait for a function to finish before executing the code below it.


4 Answers

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();
like image 193
aularon Avatar answered Oct 07 '22 20:10

aularon


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>
like image 26
Reboot Avatar answered Oct 07 '22 18:10

Reboot


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/

like image 5
Cipi Avatar answered Oct 07 '22 18:10

Cipi


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.

<!-- This div is the trick.  -->
<div id="trick" onclick="onTrickClick()" />

<!-- Someone else change the value you monitored. In this case, the person will click this button. -->
<button onclick="changeValue()">Change value</button>

<script>

    // targetObj.x is the value you want to monitor.
    const targetObj = {
        _x: 0,
        get x() {
            return this._x;
        },
        set x(value) {
            this._x = value;
            // The following line tells your code targetObj.x has been changed.
            document.getElementById('trick').click();
        }
    };

    // Someone else click the button above and change targetObj.x.
    function changeValue() {
        targetObj.x = targetObj.x + 1;
    }

    // This is called by the trick div. We fill the details later.
    let onTrickClick = function () { };

    // Use Promise to help you "wait". This function is called in your code.
    function waitForChange() {
        return new Promise(resolve => {
            onTrickClick = function () {
                resolve();
            }
        });
    }

    // Your main code (must be in an async function).
    (async () => {
        while (true) { // The loop is not for pooling. It receives the change event passively.
            await waitForChange(); // Wait until targetObj.x has been changed.
            alert(targetObj.x); // Show the dialog only when targetObj.x is changed.
            await new Promise(resolve => setTimeout(resolve, 0)); // Making the dialog to show properly. You will not need this line in your code.
        }
    })();

</script>
like image 3
Homer Liu Avatar answered Oct 07 '22 18:10

Homer Liu