web-dev-qa-db-ja.com

JavaScriptでロックを実装する方法

C#のlockと同等のものをJavaScriptに実装するにはどうすればよいですか?

だから、私が考えている簡単なユースケースを説明するのは:

ユーザーがボタンBをクリックします。 Bはonclickイベントを発生させます。 Bevent-stateにある場合、イベントはBready-stateにあるのを待ってから伝播します。 Bready-stateにある場合、Bはロックされ、event-stateに設定され、イベントが伝播します。イベントの伝播が完了すると、Bready-stateに設定されます。

ボタンにクラスready-stateを追加および削除するだけで、これに近いことがどのように行われるかがわかりました。ただし、問題は、ユーザーが変数を設定するよりも速くボタンを2回連続でクリックできるため、状況によってはこのロックの試行が失敗することです。

JavaScriptで失敗しないロックを実装する方法を知っている人はいますか?

69
smartcaveman

ロックは、スレッドレスで並行性保護を必要としないことを意図したJSの疑わしいアイデアです。遅延実行の呼び出しを組み合わせたいと考えています。このために従うパターンは、コールバックの使用です。このようなもの:

var functionLock = false;
var functionCallbacks = [];
var lockingFunction = function (callback) {
    if (functionLock) {
        functionCallbacks.Push(callback);
    } else {
        $.longRunning(function(response) {
             while(functionCallbacks.length){
                 var thisCallback = functionCallbacks.pop();
                 thisCallback(response);
             }
        });
    }
}

DOMイベントリスナーまたはpubsubソリューションを使用してこれを実装することもできます。

80
JoshRivers

JavaScriptは、ごく少数の 例外 (Firefoxの一部のバージョンではXMLHttpRequestonreadystatechangeハンドラー) イベントループコンカレント です。したがって、この場合、ロックについて心配する必要はありません。

JavaScriptには、「イベントループ」に基づく並行性モデルがあります。このモデルは、CやJavaなどの他の言語のモデルとはまったく異なります。

...

JavaScriptランタイムには、処理されるメッセージのリストであるメッセージキューが含まれています。各メッセージには機能が関連付けられています。スタックが空の場合、メッセージはキューから取り出されて処理されます。処理は、関連する関数の呼び出しで構成されます(したがって、初期スタックフレームを作成します)。メッセージ処理は、スタックが終了すると終了します。再び空になります。

...

各メッセージは、他のメッセージが処理される前に完全に処理されます。これは、プログラムを推論するときに、関数が実行されるたびに、横取りすることはできず、他のコードが実行される前に完全に実行されます(関数が操作するデータを変更できます)。 Cとは異なり、たとえば、関数がスレッドで実行される場合、任意の時点で停止して別のスレッドで他のコードを実行できます。

このモデルの欠点は、メッセージの完了に時間がかかりすぎると、Webアプリケーションがクリックやスクロールなどのユーザーインタラクションを処理できないことです。ブラウザは、「スクリプトの実行に時間がかかりすぎる」ダイアログでこれを軽減します。 従うべき良い習慣は、メッセージ処理を短くし、可能であれば1つのメッセージを複数のメッセージに切り捨てることです

イベントループの同時実行に関するその他のリンクについては、 [〜#〜] e [〜#〜] を参照してください。

30
Mike Samuel

ロックは、マルチスレッドシステムで必要な概念です。ワーカースレッドを使用しても、メッセージはワーカー間で値によって送信されるため、ロックは不要です。

ボタンの間にセマフォ(フラグシステム)を設定するだけでよいと思います。

6
James Westgate

私は成功しました mutex-promise

私はあなたの場合にロックする必要がないかもしれないという他の答えに同意します。しかし、JavaScriptをロックする必要がないというのは事実ではありません。同時実行性を処理しない外部リソースにアクセスする場合、相互排他性が必要です。

6
Tim Scott

イベントを終了した後、ボタンを無効にして有効にしないのはなぜですか?

<input type="button" id="xx" onclick="checkEnableSubmit('true');yourFunction();">

<script type="text/javascript">

function checkEnableSubmit(status) {  
  document.getElementById("xx").disabled = status;
}

function yourFunction(){

//add your functionality

checkEnableSubmit('false');
}

</script>

ハッピーコーディング!!!

2
Ravia

私の場合によると、JoshRiverの答えへの追加。

var functionCallbacks = [];
    var functionLock = false;
    var getData = function (url, callback) {
                   if (functionLock) {
                        functionCallbacks.Push(callback);
                   } else {
                       functionLock = true;
                       functionCallbacks.Push(callback);
                        $.getJSON(url, function (data) {
                            while (functionCallbacks.length) {
                                var thisCallback = functionCallbacks.pop();
                                thisCallback(data);
                            }
                            functionLock = false;
                        });
                    }
                };

// Usage
getData("api/orders",function(data){
    barChart(data);
});
getData("api/orders",function(data){
  lineChart(data);
});

API呼び出しは1つだけで、これら2つの関数は同じ結果を消費します。

0
Kadir Can