如何让程序等待 javascript 中的变量更改?

IT技术 javascript variables wait
2021-02-19 21:27:37

我想强制 JavaScript 程序在其执行的某些特定点等待,直到变量发生更改。有没有办法做到这一点?我已经找到了一个名为“narrative JavaScript”的扩展,它强制程序等待事件发生。有没有办法创建一个新事件,例如一个“变量更改事件”,其行为类似于 onclick 事件..

6个回答

2018 年编辑:请查看Object getter 和 setter以及Proxies下面的旧答案:


一个快速简单的解决方案是这样的:

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();
谢谢大家的答案!但在所有解决方案中,程序都不会阻塞!它将继续正常执行,如果在执行期间变量发生变化,则会调用回调。但是,我想要做的是强制程序阻止其执行,直到变量更改(通过调用函数),然后从被阻止的这一点继续!有任何想法吗?
2021-04-20 21:27:37
像这个人一样,让变量触发你想要的方法。这样方法就不会等待任何东西,它会在变量准备好时被调用。jsfiddle.net/cDJsB
2021-04-24 21:27:37
@Skilldrick,是的,我的意思是,我修复了它。谢谢指正:)
2021-05-03 21:27:37
我想你的意思是something===something_cachedValue然后它工作:jsfiddle.net/pEnYC
2021-05-07 21:27:37
现在编辑,它每 50 毫秒检查一次并适用于非布尔值。正如我所说的快速简便的方法,请点击此链接:stackoverflow.com/questions/1029241/...(已由@mplungjan 发布)以获得更深入的问题证明解决方案。
2021-05-09 21:27:37

JavaScript 解释器是单线程的,所以当代码在其他一些不改变变量的代码中等待时,变量永远不会改变。

在我看来,将变量包装在某种具有 getter 和 setter 函数的对象中将是最好的解决方案。然后可以在调用对象的 setter 函数时调用的对象中注册回调函数。然后,您可以在回调中使用 getter 函数来检索当前值:

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

这可以像这样轻松使用:

<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>
如果您可以控制原始变量,这可能是最好的解决方案。
2021-04-21 21:27:37
谢谢你的回答,但这不是我想要的。请看我对 aularon 的评论!
2021-04-23 21:27:37
正如我所解释的,JavaScript 解释器是单线程的。您不能阻塞线程并使其等待其他线程更改变量,因为没有其他线程可以更改变量。当另一个事件处理程序正在执行时,不能执行任何 JavaScript 事件处理程序。
2021-04-27 21:27:37
它按描述工作。谢谢!!!这非常有帮助。我需要在函数 Wrapper(callback)) 中去掉额外的右括号。
2021-05-02 21:27:37

我会推荐一个包装器来处理被改变的值。例如,您可以拥有 JavaScript 函数,如下所示:

​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();
    }


}

然后您可以从中创建一个对象,该对象将保存您要监视的值,以及一个将在值更改时调用的函数。例如,如果您想在值更改时收到警报,并且初始值为 10,您可以编写如下代码:

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

Handlerfunction(){alert("Value changed!");}将在被调用时被调用(如果您查看代码)SetValue()

你可以获得这样的value:

alert(myVar.GetValue());

您可以像这样设置值:

myVar.SetValue(12);

紧接着,屏幕上将显示警报。看看它是如何工作的:http : //jsfiddle.net/cDJsB/

谢谢你的回答,但这不是我想要的。请看我对 aularon 的评论!
2021-05-14 21:27:37

对我有用的(我到处查看并最终使用了某人的 jsfiddler / 对其进行了很小的修改 - 效果很好)是将该变量设置为具有 getter 和 setter 的对象,然后 setter 触发正在等待的函数变量变化。

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();
    };
 };

这个问题很早以前就贴出来了,很多答案会周期性地汇集目标,如果目标不变,就会产生不必要的资源浪费。此外,大多数答案在等待原始帖子要求的更改时不会阻止程序。

我们现在可以应用纯事件驱动的解决方案。

该解决方案使用 onClick 事件来传递由值更改触发的事件。

该解决方案可以在支持 Promise 和 async/await 的现代浏览器上运行。如果您使用 Node.js,请考虑将EventEmitter作为更好的解决方案。

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