web-dev-qa-db-ja.com

javascriptの変数の変更をプログラムに待機させるにはどうすればよいですか?

変数が変更されるまで、JavaScriptプログラムを実行の特定のポイントで待機させます。それを行う方法はありますか?イベントが発生するまでプログラムを待機させる「ナラティブJavaScript」と呼ばれる拡張機能をすでに見つけました。新しいイベント、たとえばonclickイベントのように動作する「変数変更イベント」を作成する方法はありますか。

57
Thanasis Petsas

2018年編集: Object getters and setters and 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();
85
aularon

JavaScriptインタープリターはシングルスレッドであるため、変数が変更されない他のコードでコードが待機している場合、変数は変更できません。

私の意見では、ゲッターとセッターの機能を持つ何らかの種類のオブジェクトで変数をラップするのが最善の解決策だと思います。次に、オブジェクトのセッター関数が呼び出されたときに呼び出されるオブジェクトにコールバック関数を登録できます。その後、コールバックで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>
20
Reboot

変更される値を処理するラッパーをお勧めします。たとえば、次のような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!");});
_

function(){alert("Value changed!");}が呼び出されると、ハンドラーSetValue()が呼び出されます(コードを見ると)。

次のような値を取得できます。

_alert(myVar.GetValue());
_

次のように値を設定できます。

_myVar.SetValue(12);
_

そしてその直後に、アラートが画面に表示されます。仕組みをご覧ください: http://jsfiddle.net/cDJsB/

5
Cipi

propertiesを使用できます:

Object.defineProperty MDNドキュメント

例:

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
1
Eduardo Cuomo

質問はずっと前に投稿されたもので、多くの回答が定期的にターゲットをプールし、ターゲットが変更されていない場合、リソースの無駄を生み出しています。さらに、ほとんどの回答は、元の投稿で必要な変更を待っている間、プログラムをブロックしません。

これで、純粋にイベント駆動型のソリューションを適用できます。

このソリューションでは、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>
1
Homer Liu

私のために働いた(私はその場所を見て、誰かのjsfiddlerを使用して/非常にわずかに変更して-うまく機能した)ゲッターとセッターでその変数をオブジェクトに設定し、セッターが待っている関数をトリガーすることでした変数の変更。

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

時代遅れですが、これに対応する確かに良い方法です。プロジェクトのためにこれを書き上げて、共有したいと思いました。他のいくつかと同様に、スタイルが異なります。

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;
0
darcher

JavaScriptは、これまでで最悪のプログラム/スクリプト言語の1つです。

JavaScriptでは「待機」は不可能のようです! (はい、実際の生活のように、時々待つことが最善の選択肢です!)

「while」ループと「Recursion」(関数は...まで繰り返し自分自身を呼び出します)を試しましたが、JavaScriptはとにかく動作を拒否します! (これは信じられないですが、とにかく、以下のコードを参照してください。)

whileループ:

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

再帰:

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

または、以下の例のように、「静的」変数の値に基づいてタスクを実行する関数を作成できます。

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>
0
User

いいえ、独自のソリューションを作成する必要はありません。 Observerデザインパターンなどを使用するようなものです。

変数を制御できない場合、または変数を使用しているユーザーがいない場合、あなたは運命にあると思います。編集:またはSkilldrickのソリューションを使用してください!

マイク