2

だから私はjavascriptでこの機能を実装しています:ユーザーがドキュメントを開くと、そのデータは10秒ごとに保存され、ユーザーが閉じるともう一度保存されます。それは一見うまく機能します。実装は次のとおりです。

var data = "blabla";
var saveagain = false;
var t1;

function onDocumentOpen() {
    saveagain = true;
    savedata();
}

function onDocumentClose() {
    saveagain = false;
    savedata();
}

function savedata() {
    if (!saveagain) clearTimeout(t1);
    SaveDataAjaxCall(data, function() {
        //data was saved
        if (saveagain) t1 = setTimeout("savedata()", 10000);
    });
}

私のアプローチが正しいかどうか、次のような極端な状況で競合状態につながる可能性があるかどうか疑問に思っていました。

onDocumentClose() から呼び出された savedata() インスタンスが if(!saveagain) ステップの後にある場合、setTimeout() の前のタイマーから呼び出された savedata() インスタンスはそのステップの前にあるため、もう一度呼び出されます。これまたはもっと奇妙なことが起こりますか?

前もって感謝します

編集:

TJ Crowder と Bengi のコメントを検討した後、次のようにコードを完成させました。

var data = "";
var saveagain = false;
var t1;
var beingsaved = false;

function onDocumentOpen() {
    saveagain = true;
    savedata();
}

function onDocumentClose() {
    saveagain = false;
    savedata();
}

function saveData() {
    if (beingsaved) {
        if (!saveagain) setTimeout(saveData, 100);
        return false;
    }
    beingsaved=true;

    if (!saveagain) clearTimeout(t1);

    data=getData();

    SaveDataAjaxCall(data, function() {
        //data was saved
        beingsaved=false;
        if (saveagain) t1 = setTimeout(saveData, 10000);
    });

}

私は今、あらゆる機会に対応してきたと思います。beingsaved の解決策は、TJ Crowder が提案したアトミック カウンターと同じだと思います。

EDIT2: うーん、onDocumentClose 呼び出しによって beingsaved が true に設定される直前に、setTimeout 呼び出しによって if(beingsaved) が評価される場合があるため、解決したかどうかはわかりません。これは起こりえますか?

4

2 に答える 2

2

すべての適切な ajax 操作がそうであるように、保存操作は非同期であると思います。その場合、2 つの保存トリガーが重複しないように、何らかのガード条件を配置する必要があります。または、もちろん、オーバーラップを許可しますが、サーバー側で (おそらくシーケンス番号またはタイムスタンプを使用して) 処理します。後者の保存が既にコミットされている場合、以前の保存は無視されます。

于 2012-05-21T17:30:43.937 に答える
1

いいえ、Javascript はシングルスレッドです (イベントベースのインターフェースで通信する必要がある WebWorkers や Co などのイノベーションは別として)。

したがって、同期実行 (グローバル スクリプト、タイムアウト、ajax イベント ハンドラー) が開始されると、それは実行され、停止することはできません。他のすべて (新しいイベント、0ms-timeouts など) は後でスケジュールされます。

スクリプトには、タイムアウトと ajax コールバックの 2 つの非同期シナリオが含まれています。ループ onDocumentOpen を開始すると、次のようになります。

  1. saveData の実行: ajax リクエストの開始
  2. 待機 (ajax イベントが発生するまで)
  3. 成功コールバックの実行: saveData の新しいタイムアウトを設定します
  4. 待機(タイムアウトイベントが発生するまで)
  5. saveData の実行: ajax リクエストの開始
  6. 待つ...

...等々。

onDocumentClose は、他の実行が実行されていない待機期間中にのみ実行できます。次のことを期待します。

  1. ... saveData の実行: ajax リクエストの開始
  2. 何も起こりません
  3. ajax イベント: 成功コールバックの実行: saveData の新しいタイムアウトを設定します
  4. 何も起こりません
  5. documentClose イベント: タイムアウトをクリアし、ajax リクエストを開始します
  6. 何も起こりません
  7. ajax イベント: 成功コールバックの実行: 新しいタイムアウトを設定しなくなりました。終わり。

しかし、ajax リクエスト中に documentClose が発生した場合、ケースは保護されませんでした。

  1. ... saveData の実行: ajax リクエストの開始
  2. 何も起こりません
  3. ajax イベント: 成功コールバックの実行: saveData の新しいタイムアウトを設定します
  4. 何も起こりません
  5. timeout イベント: saveData の実行、ajax リクエストの開始
  6. 何も起こりません
  7. documentClose イベント: (存在しない) タイムアウトをクリアし、ajax リクエストを開始します (2 回目)
  8. 何も起こりません
  9. ajax イベントの 1 つ: execute success callback: は、新しいタイムアウトを設定しなくなりました。
  10. 何も起こりません
  11. その他の ajax イベント: 成功コールバックの実行: 新しいタイムアウトを設定しなくなりました。終わり。

だから必ず終わりが来る。何かの実行中にイベントの 1 つが発生した場合、その間に「何も起こらない」ということはありませんが、次々と実行されます。ajax コールバックの実行中、タイムアウトがクリアされる前に終了する必要がある場合でも、終了後にクリアされるとスケジュールが解除されます。

var id = setTimeout(function(){
    alert("still waiting for execution"); // never alerts
}, 500);
setTimeout(function(){
    alert("still waiting for execution"); // this alerts
}, 500);
for(var d = Date.now(); Date.now()-d < 1000; ) {
    ; // wait - the timeouts end during this heavy processing
}
clearTimeout(id);
于 2012-05-21T17:30:46.493 に答える