最近、かなり厄介なバグに遭遇しました。コードが<select>
JavaScript 経由で を動的にロードしていたのです。動的にロードされたこの要素には、<select>
事前に選択された値がありました。IE6 では、以下のようにの値が selectedの属性と同期していないことが<option>
あるため、 selected を修正するコードが既にありました。<select>
selectedIndex
<option>
index
field.selectedIndex = element.index;
しかし、このコードは機能しませんでした。フィールドがselectedIndex
正しく設定されているにもかかわらず、間違ったインデックスが選択されてしまいます。ただし、alert()
適切なタイミングでステートメントを挿入すると、正しいオプションが選択されます。これは何らかのタイミングの問題かもしれないと思い、以前コードで見たことのあるランダムな方法を試しました。
var wrapFn = (function() {
var myField = field;
var myElement = element;
return function() {
myField.selectedIndex = myElement.index;
}
})();
setTimeout(wrapFn, 0);
そしてこれはうまくいきました!
問題の解決策は見つかりましたが、なぜこれで問題が解決するのか正確にはわからないので不安です。公式の説明を持っている人はいますか? を使用して関数を「後で」呼び出すことで、どのようなブラウザの問題を回避していますかsetTimeout()
?
ベストアンサー1
質問には、競合状態間:
- ブラウザはドロップダウンリストを初期化し、選択されたインデックスを更新する準備を整え、
- 選択したインデックスを設定するコード
あなたのコードはこの競争に常に勝ち、ブラウザの準備が整う前にドロップダウン選択を設定しようとしていたため、バグが発生していました。
この競争が存在するのは、JavaScriptが単一実行スレッドこれはページのレンダリングと共有されます。実際には、JavaScript を実行すると DOM の更新がブロックされます。
回避策は次のとおりです:
setTimeout(callback, 0)
コールバックを指定して呼び出しsetTimeout
、2 番目の引数として 0 を指定すると、可能な限り短い遅延 (タブにフォーカスがあり、実行中の JavaScript スレッドがビジーでない場合は約 10 ミリ秒) の後に、コールバックが非同期的に実行されるようにスケジュールされます。
したがって、OP の解決策は、選択されたインデックスの設定を約 10 ミリ秒遅らせることでした。これにより、ブラウザは DOM を初期化する機会を得て、バグを修正しました。
Internet Explorer のすべてのバージョンで奇妙な動作が見られ、この種の回避策が必要になる場合もありました。あるいは、OP のコードベースに実際にバグがあった可能性もあります。
フィリップ・ロバーツの講演を見る「イベントループって一体何なの?」より詳しい説明については。