27

私のユーザーには、基本的にはスプレッドシートの簡素化されたバージョンが表示されます。グリッドの各行にテキスト ボックスがあります。テキスト ボックスの値を変更すると、入力の検証を実行し、グリッドを駆動するコレクションを更新し、ページの小計を再描画します。これはすべてOnChange、各テキストボックスのイベントによって処理されます。

ユーザーがボタンをクリックするとSave、ボタンのOnClickイベントを使用して金額の最終的な検証を行い、入力内容全体を Web サービスに送信して保存します。

少なくとも、フォームをタブでSubmitボタンに移動すると、それが起こります。

問題は、値を入力してすぐに保存ボタンをクリックすると、完了SaveForm()する前に実行が開始UserInputChanged()され、競合状態になることです。私のコードでは を使用していませんが、遅い検証コードsetTimeoutをシミュレートするために使用しています。UserInputChanged

 <script>
  var amount = null;
  var currentControl = null;

  function UserInputChanged(control) {
      currentControl = control;
      // use setTimeout to simulate slow validation code
      setTimeout(ValidateAmount, 100);
  }

  function SaveForm() {
      // call web service to save value
      document.getElementById("SavedAmount").innerHTML = amount;
  }

  function ValidateAmount() {
      // various validationey functions here
      amount = currentControl.value; // save value to collection
      document.getElementById("Subtotal").innerHTML = amount;
  }
</script>

Amount:   <input type="text" onchange="UserInputChanged(this)">
Subtotal: <span id="Subtotal"></span>
<button onclick="SaveForm()">Save</button>
Saved amount: <span id="SavedAmount"></span>

検証コードを高速化できるとは思いません。かなり軽量ですが、検証が完了する前にコードが Web サービスを呼び出そうとするほど遅いようです。

私のマシンでは、コードの保存が始まる前に検証コードが実行されるかどうかの間のマジック ナンバーは ~95ms です。これは、ユーザーのコンピューターの速度に応じて、より高くなったり低くなったりする場合があります。

この状態を処理する方法を知っている人はいますか? 同僚は、検証コードの実行中にセマフォを使用し、保存コードでビジー ループを使用してセマフォのロックが解除されるまで待機することを提案しましたが、コードでビジー ループを使用することは避けたいと思います。

4

7 に答える 7

27

セマフォを使用します (StillNeedsValidating と呼びましょう)。SaveForm 関数は、StillNeedsValidating セマフォが起動していることを確認した場合、独自の 2 番目のセマフォ (ここでは FormNeedsSaving と呼びます) をアクティブにして戻ります。FormNeedsSaving セマフォが起動している場合、検証関数が終了すると、それ自体で SaveForm 関数が呼び出されます。

ジャンクコードで;

function UserInputChanged(control) {
    StillNeedsValidating = true;
    // do validation
    StillNeedsValidating = false;
    if (FormNeedsSaving) saveForm(); 
}

function SaveForm() {
    if (StillNeedsValidating) { FormNeedsSaving=true; return; }
    // call web service to save value
    FormNeedsSaving = false;
}
于 2008-12-03T18:08:24.160 に答える
11

検証中は保存ボタンを無効にします。検証が最初に行うように無効に設定し、終了したら再度有効にします。

例えば

function UserInputChanged(control) {
    // --> disable button here --< 
    currentControl = control;
    // use setTimeout to simulate slow validation code (production code does not use setTimeout)
    setTimeout("ValidateAmount()", 100); 
}

function ValidateAmount() {
    // various validationey functions here
    amount = currentControl.value; // save value to collection
    document.getElementById("Subtotal").innerHTML = amount; // update subtotals
    // --> enable button here if validation passes --<
}

setTimeout を削除して検証を 1 つの関数にする場合は調整する必要がありますが、ユーザーが超人的な反射神経を持っていない限り、問題なく使用できます。

于 2008-12-03T18:10:48.307 に答える
4

セマフォまたはミューテックスがおそらく最善の方法ですが、ビジーループの代わりに、を使用しsetTimeout()てスレッドスリープをシミュレートします。このような:

busy = false;

function UserInputChanged(control) {
    busy = true;
    currentControl = control;
    // use setTimeout to simulate slow validation code (production code does not use setTimeout)
    setTimeout("ValidateAmount()", 100); 
}

function SaveForm() {
    if(busy) 
    {
       setTimeout("SaveForm()", 10);
       return;
    }

    // call web service to save value
    document.getElementById("SavedAmount").innerHTML = amount;
}

function ValidateAmount() {
    // various validationey functions here
    amount = currentControl.value; // save value to collection
    document.getElementById("Subtotal").innerHTML = amount; // update subtotals
    busy = false;
}
于 2008-12-03T18:13:50.187 に答える
4

タイムアウトが問題を引き起こしていると思います...それがプレーンコード(非同期AJAX呼び出し、タイムアウトなどなし)になる場合、UserInputChangedが完了する前にSaveFormが実行されるとは思いません。

于 2008-12-03T18:09:00.883 に答える
0

非同期データ ソースを操作する場合、JavaScript プロセス スレッドは、リモート データ ソースからまだ返されていないデータに依存するディレクティブを実行し続けるため、競合状態が発生する可能性があります。そのため、コールバック関数があります。

あなたの例では、検証コードの呼び出しには、検証が戻ったときに何かを実行できるコールバック関数が必要です。

ただし、複雑なロジックで何かを作成したり、既存の一連のコールバックをトラブルシューティングまたは拡張しようとしたりすると、頭がおかしくなることがあります。

それが、proto-q ライブラリを作成した理由です: http://code.google.com/p/proto-q/

このタイプの作業が多い場合は、チェックしてください。

于 2010-09-17T17:47:25.077 に答える
0

グリッド全体の状態を監視し、グリッド全体が有効かどうかを示すイベントを発生させる繰り返し関数を設定できます。

「フォームを送信」ボタンは、そのステータスに基づいて有効または無効になります。

ああ、今も同様の反応が見られます。もちろん、これも機能します。

于 2008-12-03T18:12:48.910 に答える
-3

競合状態はありません.javascriptはシングルスレッドであるため、競合状態はjavascriptで発生することはありません.2つのスレッドが互いに干渉することはありません.

あなたが与える例はあまり良い例ではありません。setTimeout 呼び出しは、呼び出された関数を JavaScript エンジンのキューに入れ、後で実行します。その時点で保存ボタンをクリックすると、保存が完全に終了するまで setTimeout 関数は呼び出されません。

あなたの JavaScript でおそらく起こっていることは、onChange イベントが呼び出される前に onClick イベントが JavaScript エンジンによって呼び出されることです。

ヒントとして、javascript デバッガー (firebug、microsoft screipt デバッガー) を使用しない限り、javascript はシングル スレッドであることに注意してください。これらのプログラムは、スレッドをインターセプトして一時停止します。その時点から、(イベント、setTimeout 呼び出し、または XMLHttp ハンドラーのいずれかを介して) 他のスレッドを実行できるようになり、javascript が同時に複数のスレッドを実行できるように見えます。

于 2008-12-03T19:55:30.747 に答える