2009-05-09 10 views
10

JavaScriptコードで同期を実行するソリューションが存在するのはいつも不思議でした。たとえば、私は次のような場合があります。AJAX呼び出しからいくつかの応答値をキャッシュしようとしています。問題は、複数の呼び出しを同時に行うことができるため、コード内の競合状態になります。ですから私はそれを解決するために非常に興味がありますか?どんな人もやるべきことを持っていますか?JavaScript同期オプション

答えて

4

私の問題の解決策を見つけました。私が探していたほど完璧ではないと言わなければならないが、これまでのところうまくいき、一時的に回避していると思う。

$.post("url1", function(data) 
{ 
    // do some computation on data and then 
    setSomeValue(data); 
}); 

var setSomeValue = (function() 
{ 
    var cache = {}; 
    return function(data) 
    { 
     if (cache[data] == "updating") 
     { 
      setTimeout(function(){ setSomeValue(data);}, 100); 
      return; 
     } 
     if (!cache[date]) 
     { 
      cache[date] = updating; 
      $.post("url2", function(another_data) 
      { 
        //make heavy computation on another_data 
        cache[data] = value; 
        // update the UI with value 
      }); 
     } 
     else 
     { 
      //update the UI using cached value 
     } 
    } 
})(); 
+0

ありがとうございます。私は、「それはシングルスレッドなので、問題ではない」と多くの人が驚いています。これは、非同期コールバックを持つ世界ではまったく間違っています。あなたは問題をうまく説明しましたが、これは私にとって完全に効果的なアプローチです。 –

6

Javascriptは、少なくとも通常のブラウザ環境では、本質的にシングルスレッドです。同じ文書にアクセスするスクリプトを同時に2回実行することはありません。 (新しいJavascriptワーカースレッドはここでは例外かもしれませんが、メッセージの受け渡しだけで通信するために、ドキュメントにまったくアクセスするつもりはありません)。

+1

JavaScriptはシングルスレッドでもかまいませんが、競合状態が発生する可能性があります。非同期要求が完了したときなどの順序は保証されません。これは特にFirefoxアドオンと複数のウィンドウで当てはまります。 –

+1

あなたが明示的に問題を処理できるコードを書く必要があります。これは、メモリからの不完全な結果を読み込んだり、大規模な操作の間で変更を上書きしたりすることによってスレッドが互いに干渉するのを防ぐために、他の言語で必要な同種の同期ではありません。 ブラウザ環境でJavaScript実行のアクティブなストリームは1つだけです。すべてのイベントハンドラは、連続して呼び出されます。 – fforw

+1

ちょうど1つのAJAX呼び出しを記述してから、ハンドラで別のAJAX要求を呼び出し、2番目のハンドラでいくつかのグローバル変数にアクセスしようとします。そして今、最初の呼び出しのいくつかの反復を行います。その変数へのシリアライズされたアクセスが存在することは確実ですか?注文を予測できますか?私がここで質問したことのない問題のために作業コードを書くことができればもう一つのことがあります。 –

3

はい、非IEでasynch optionを開いているメソッドで、IEブラウザのdo the sameでbAsyncパラメータでfalseに設定して、xmlHttpRequestsを同期させることができます。

何らかの理由でリクエストをチェーンしたいことがあります。キュースタックを作成し、リクエストを送信します。

+1

同期リクエストは、他のすべてのJavaScriptイベントハンドラの実行を妨げるため、悪いです。 – fforw

+0

私はちょうど彼の質問に答えた、私は彼の必要性を判断しようとしなかった。それを下降させる? heh。 –

+0

人は、より多くのユーザー入力を処理する前にリクエストを処理したいなど、さまざまな理由で同期が必要な場合があります。他にも理由があります。等 –

3

まず、すべての現在のJS実装がシングルスレッドであることを知っておくことが重要です。そのため、通常は競合条件と同期の状況については検討していません。

サイドノートとして、ブラウザでJSの並行処理を可能にするワーカースレッドが導入されましたが、今のところこれは当てはまりません。

とにかく、あなたはまだフォームの非同期呼び出しを受け取ることを期待しているデータに問題があり、あなたが受け取る順序については保証がありません。

JSは、コールバックを使用してこれに非常に良いソリューションを提供します。それぞれの非同期イベントに対して、適切なコールバック関数を添付して送信し、適切にイベントを処理します。 同期は、それを意味する意味で、そこで起こっているはずです。

+0

私の場合、私はサーバーからのいくつかの応答のキャッシュを構築しようとしています。 AJAX呼び出しには独自のハンドラがありますが、ハンドラには関数の呼び出しがあり、キャッシュ変数にアクセスし、変数が設定されている場合はそれを上書きして別のAJAX呼び出しを行います。したがって、非同期呼び出しを使用している場合は、キャッシュの更新を見逃して不要な呼び出しを2回実行する可能性があります。この動作は不本意なので、その変数の読み取り/書き込みアクセスを同期させる方法を考えていました。私はsome_lengthを<;; ++ I) $ .post( "URL"、機能(データ) { setUpSomeValue(データ)は、i = 0(VARため $(関数(){ : –

8

私は可能な解決法を提供することができますが、コードを見ることなく...あなたがしていることを完全には確認していませんが、これを行うことができなかった理由はありません。

のjQueryでの基本コード:(テストと略さ...しかし、私は同様のことを行っているではない)

var needAllThese = {}; 

$(function(){ 

     $.ajax("POST","/somepage.aspx",function(data) { 
      needAllThese.A = "VALUE"; 
     }); 

     $.ajax("POST","/somepage2.aspx",function(data) { 
      needAllThese.B = "VALUE"; 
     }); 

     $.ajax("POST","/somepage3.aspx",function(data) { 
      needAllThese.C = "VALUE"; 
     }); 

     startWatching(); 
}); 

function startWatching() { 
    if (!haveEverythingNeeded()) { 
     setTimeout(startWatching,100); 
     return; 
    } 
    everythingIsLoaded(); 
} 

function haveEverythingNeeded() { 
    return needAllThese.A && needAllThese.B && needAllThese.C; 
} 

function everythingIsLoaded() { 
    alert("Everything is loaded!"); 
} 

EDIT:(再:あなたのコメント)あなたはコールバックに

探しています、同じ方法でjQueryがそれを行います。

var cache = {}; 

    function getSomeValue(key, callback) { 
     if (cache[key]) callback(cache[key]); 

     $.post("url", function(data) { 
      setSomeValue(key,data); 
      callback(cache[key]); 
     }); 
    } 

    function setSomeValue(key,val) { 
     cache[key] = val; 
    } 

    $(function(){  
     // not sure you would need this, given the code above 
     for (var i = 0; i < some_length; ++i) { 
      $.post("url", function(data){ 
       setSomeValue("somekey",data); 
      }); 
     } 

     getSomeValue("somekey",function(val){    
      $("#element").txt(val);    
     };    
    }); 
+0

コードは次のようになります; }); するvar setUpSomeValue =(関数(){ VARキャッシュ= {} 復帰機能(データ) {IF(キャッシュ[データ]!) $ .post(.....) //新しいデータでキャッシュを更新する そうでなければキャッシュ[データ]を返す; } })(); したがって、2つの同様のデータi私はキャッシュの更新について通知することができないので、私はまだ2番目のAJAX呼び出しを行っています。だからこそ私はそこでいくつかの同期をとることを考えているのです。 –

+0

正直言って、最後の解決策が私の問題でどのように役立つのか分かりません。少し説明してもらえますか? –

+0

あなたが尋ねたこととまったく同じです。コールバックを使用する...あなたのコメントにサンプルコードを書いた場合、$ postコールでコールバックを使用しているのと同じコンセプトです...コードを書かない限り、それを理解するのに問題はありません –

1

私はそれが後になっていることを知っていますが、私は改善を与えると思っていました。 Artem Bargerは、キャッシュされた値が "更新中"の場合にsetTimeoutを使用する独自のソリューションを開発しました...代わりに、実際にキャッシュされたデータと関数のキューを保持するオブジェクトを持つように、データが返されたらキャッシュされたデータを呼び出す。

したがって、「更新中」の場合、項目データにリンクされたキューに関数を追加するだけで、データが返されます。データを設定してから、関数のキュー(コールバック)を繰り返し処理し、返されたデータで呼び出します。

テクニカルになりたい場合は、キューを通過する際に特定のQOSタイムアウトを設定し、繰り返しの始めにストップウォッチを設定し、特定の時間に達するとsetTimeoutを呼び出してあなたがそれを持っていることを願って:) - それは基本的に1つだけが必要とされるsetTimout呼び出しのX量を節約します。

上記のArtem Bargersコードを見ると、私が提案するものの要点を得るべきです。

関連する問題