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

Posted

技术标签:

【中文标题】如何让程序等待 javascript 中的变量更改?【英文标题】:How can I make a program wait for a variable change in javascript? 【发布时间】:2011-04-07 20:20:20 【问题描述】:

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

【问题讨论】:

我认为最好的方法是使用 rxjs 库并使用 observable 作为变量。 【参考方案1】:

基于更多功能的 Promise (async/await) 方法的示例:

var delay = require('delay');
var obj = 
  k: null
;

function notAwaitable() 
  return obj.k;


async function waitFor(f) 
  let r = f();
  while (!r) 
    console.log('Not yet, waiting more');
    await delay(1000);
    r = f();
  
  return r;


(async function() 
  await delay(5000);
  obj.k = 42;
)();

(async function() 
  let result = await waitFor(notAwaitable);
  console.log(result);
)();

【讨论】:

【参考方案2】:

对我有用的东西(我到处查看并最终使用某人的 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();
    ;
 ;

【讨论】:

【参考方案3】:

或者,您可以创建一个函数,根据其“静态”变量的值执行任务,示例如下:

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

【讨论】:

【参考方案4】:

超级过时,但肯定是适应这种情况的好方法。刚写了这个 对于一个项目,我想我会分享。与其他一些类似,风格各异。

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;

【讨论】:

【参考方案5】:

问题是很久以前的问题,很多答案会周期性地集中目标,如果目标不变,会产生不必要的资源浪费。此外,大多数答案在等待原帖要求的更改时不会阻塞程序。

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

该方案使用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>

【讨论】:

【参考方案6】:

编辑 2018:请查看 Object getters and setters 和 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();

【讨论】:

现在已编辑,它每 50 毫秒检查一次,适用于非布尔值。正如我所说的那样快速简便的方法,请点击此链接:***.com/questions/1029241/…(@mplungjan 已发布)以获得更深入的问题证明解决方案。 我想你的意思是something===something_cachedValue。然后它工作:jsfiddle.net/pEnYC @Skilldrick,是的,我的意思是,我修好了。谢谢指正:) 谢谢大家的回答!但在所有解决方案中,程序都不会阻塞!它将继续正常执行,如果变量在执行过程中发生变化,则会调用回调。但是,我想做的是强制程序阻止它的执行,直到变量改变(通过调用一个函数),然后从它被阻塞的地方继续!有什么想法吗? 像这家伙一样,让变量触发你想要的方法。这样该方法就不会等待任何东西,它会在变量准备好时被调用。 jsfiddle.net/cDJsB【参考方案7】:

您可以使用属性

Object.defineProperty MDN documentation

例子:

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

【讨论】:

【参考方案8】:

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>

【讨论】:

如果您可以控制原始变量,这可能是最好的解决方案。 感谢您的回答,但这并不是我想要的。请看我对 aularon 的评论! 正如我所解释的,JavaScript 解释器是单线程的。您不能阻塞线程并使其等待其他线程更改变量,因为没有其他线程可以更改变量。当另一个已经在执行时,不能执行任何 JavaScript 事件处理程序。 它按描述工作。谢谢!!!这很有帮助。我需要在函数 Wrapper(callback)) 中取出多余的右括号。【参考方案9】:

我会推荐一个包装器来处理被改变的值。例如你可以有 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!"););

SetValue() 被调用时,处理程序function()alert("Value changed!"); 将被调用(如果你看代码的话)。

你可以像这样获得价值:

alert(myVar.GetValue());

你可以像这样设置值:

myVar.SetValue(12);

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

【讨论】:

感谢您的回答,但这并不是我想要的。请看我对 aularon 的评论!【参考方案10】:

不,您必须创建自己的解决方案。比如使用观察者设计模式之类的。

如果你无法控制变量或谁在使用它,恐怕你注定要失败。 编辑:或使用 Skilldrick 的解决方案!

迈克

【讨论】:

@JakeJ 这就是我的意思,您必须创建自己的解决方案。

以上是关于如何让程序等待 javascript 中的变量更改?的主要内容,如果未能解决你的问题,请参考以下文章

更改 JavaScript 中的外部变量

使用 Pyads 库时如何等待变量更改?

JavaScript,当变量作为参数传递时更改函数内部的变量值[重复]

如何在 ForEach 循环之后保留对象变量更改。 Javascript

如何让 Javascript 在发送请求之前等待 Promise?

如何在同步函数中等待 JavaScript 中的异步调用?