14

実際の問題を確認するには、この jsbinを参照してください。ボタンをクリックすると、buttonHandler()次のような がトリガーされます。

function buttonHandler() {
  var elm = document.getElementById("progress");
  elm.innerHTML = "thinking";
  longPrimeCalc();
}

このコードは、div のテキストを「thinking」に変更し、longPrimeCalc()完了するまでに数秒かかる算術関数である を実行すると予想されます。しかし、これは起こりません。代わりに、"longPrimeCalc" が最初に完了し、2 行のコードの順序が逆になったかのように、実行が完了した後にテキストが "thinking" に更新されます。

ブラウザは「innerHTML」コードを同期的に実行するのではなく、独自のタイミングで実行する新しいスレッドを作成するようです。

私の質問:

  1. この動作を引き起こしているフードの下で何が起こっているのでしょうか?
  2. ブラウザーが期待どおりに動作するようにするには、つまり、" " を実行する前に "innerHTML" を強制的に更新するにはどうすればよいlongPrimeCalc()ですか?

これを最新バージョンのクロムでテストしました。

4

2 に答える 2

9

あなたの推測は間違っています。更新は同期的に完了します.innerHTML(そして、ブラウザは間違いなく新しいスレッドを作成しません)。ブラウザーは、コードが完成するまで、わざわざウィンドウを更新することはありません。ビューの更新が必要な何らかの方法で DOM に問い合わせる場合、ブラウザには選択の余地がありません。

たとえば、 を設定した直後に、次のinnerHTML行を追加します。

var sz = elm.clientHeight; // whoops that's not it; hold on ...

編集— ブラウザをだます方法を見つけ出すかもしれませんし、不可能かもしれません。長い計算を別のイベントループで起動すると、それが機能することは確かです。

setTimeout(longPrimeCalc, 10); // not 0, at least not with Firefox!

ここでの良い教訓は、ブラウザはページ レイアウトの無意味なリフローを行わないように努めているということです。あなたのコードが素数の休暇中に消えてしまい、戻ってきてinnerHTML 再びを更新した場合、ブラウザは無意味な作業を節約できたでしょう。更新されたレイアウトを描画していない場合でも、ブラウザは、要素のサイズや位置などを調べたときに一貫した回答を提供するために、DOM に何が起こったのかを把握する必要があります。

于 2013-05-27T15:49:02.067 に答える
4
  1. 現在実行中のコードが最初に完了し、次にすべてのページの更新が完了するという仕組みだと思います。この場合、呼び出しlongPrimeCalcによってさらに多くのコードが実行され、それが完了したときにのみページ更新が変更されます。

  2. これを修正するには、現在実行中のコードを終了させて​​から、別のコンテキストで計算を開始する必要があります。でそれを行うことができますsetTimeout。それ以外に方法があるかどうかはわかりません。

これは、動作を示すjsfiddleです。にコールバックを渡す必要はありませんlongPrimeCalc。戻り値で必要なことを行う別の関数を作成するだけです。基本的に、計算を実行の別の「スレッド」に延期する必要があります。このようにコードを書くと、あなたが何をしているのかが明らかになります (潜在的により良くするために再度更新されます):

function defer(f, callback) {
  var proc = function() {
    result = f();
    if (callback) {
      callback(result);
    }
  }
  setTimeout(proc, 50);
}

function buttonHandler() {
  var elm = document.getElementById("progress");
  elm.innerHTML = "thinking...";
  defer(longPrimeCalc, function (isPrime) {
    if (isPrime) {
      elm.innerHTML = "It was a prime!";
    }
    else {
      elm.innerHTML = "It was not a prime =(";
    }
  });
}
于 2013-05-27T16:15:38.030 に答える