16

常にカウントダウンしているタイマーがある Web アプリケーションがあります。その間、クライアントはサーバーを頻繁にチェックして、タイマーにさらに時間が追加されているかどうかを確認します。コードは次のようになります。

function tick() {
    // This function is called once every second
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    time = newtime;
};

もちろん、それよりも少し複雑ですが、固有の競合状態を見ることができます。update 関数と tick 関数の両方がtime同時に変更しようとしている場合はどうなるでしょうか?

率直に言って、私はこの種の同時実行性の問題に対処する方法を理解するのに十分な JavaScript をほとんど知りません。これを行う簡単な方法はありますか、そうでない場合は、もっと学ぶことができるリソースを教えてもらえますか?

ありがとうございました。

4

5 に答える 5

16

Javascript は同時に実行されないため、競合状態はありません。

非同期操作 (AJAX など) からコールバックが発生するたびに、setTimeout別の非同期操作から別のコールバックを呼び出す前に、そのコールバックの実行を終了する必要があります。したがって、update()実行中の場合、他の Javascript はありません。終了したらupdate()、非同期操作からの他のコールバックを起動できます (例: tick())。興味深いことに、これがsetTimeout、タイムアウトに達した正確な瞬間に実行されることが保証されていない理由でもあります。他の JavaScript がコールバックの実行をブロックしている可能性があります。

http://ejohn.org/blog/how-javascript-timers-work/をチェックして、これらすべてがどのように機能するかについての良い情報を確認してください。

于 2010-01-16T19:36:49.197 に答える
8

Javascript はシングルスレッドです。競合状態はありません。実行中に2 つの行をオーバーラップさせる方法は JavaScript にはありませtime = newtime;time -= 1;。実際、2 つの関数は重複しないことが保証されています。そのうちの 1 つが実行され、次にもう 1 つが実行されます。

于 2010-01-16T19:35:47.513 に答える
0

私は間違っていました: これでは問題は解決しません! (コードの後の説明)

NEWTIME = false;
function tick() {
    // This function is called once every second
    if (NEWTIME) {
        time = NEWTIME;
        NEWTIME = false;
    }
    time -= 1;
    redisplay(time);
};
function update(newtime) {
    // This function is called whenever the ajax request
    // to the server yields a new time
    NEWTIME = newtime;
};

この間違った解決策の問題点は、この方法で競合状態の問題を variable から variable に移動するだけであるということtimeですNEWTIME

これを考えてみてください: の実行は今tick行に到達して実行し、time = NEWTIME;続行する前に update get が呼び出されNEWTIMEて値を取得しますX。現在、ティックの実行は実行を続けていNEWTIME = false;ます。このようにして、X値が失われNEWTIME、 update() 呼び出しの効果が失われます!

于 2010-01-16T17:37:18.927 に答える
-1

問題にはいくつかのセマフォが必要です。前のものが終わった後にajaxを送るために私はそれをたくさんします。あなたのケースは少し似ています;)

そのようなことを試してください。ajaxコールバックと衝突する時間をデクリメントするすべての試みを無視する必要があります。

window.TimeKeeper = new function(){
this.time=0; //initial value, whatever
this.isopen=true;

this.decrement = function(){ 
 if(this.isopen){
  this.time--;
  redisplay(this.time);
  }
 }
this.set = function(val){
 if(this.isopen){
  this.isopen=false;
  this.time=val;
  this.isopen=true;
  } else {
  //another AJAX callback is modifying time. 
   //You can enqueue current value and put it later
  }
 }

}

function tick() {
    TimeKeeper.decrement();

};
function update(newtime) {
    TimeKeeper.set(newtime);
};

もう1つ、setTimeoutは新しいスレッドのように機能し、ブラウザーが同期memアクセスを実行することを期待しているため、デクリメントする前に値が増加しなかったかどうかを確認するだけで十分な場合があります。しかし、上記のソリューションはより柔軟で安全です。

そして、ちょっとしたヒント-AJAXで頻繁にクエリを実行することは避けてください-リクエストが送信された順序とは異なる順序で返される、Firefoxのメモリ使用量が1分間にあまりにも多くのajaxで蓄積されるなど、余分な問題が発生する可能性があります;)

于 2010-01-16T19:14:09.323 に答える
-2

現在の時刻にさらに数秒追加する限り、問題はありません。

time = newtime;トライする代わりにこうtime += newtime;すれば気になる秒を逃しません。

それでも、最悪の場合でも 1 秒しか失うことはありません。

于 2010-01-16T17:17:43.947 に答える