[解決済み] setTimeout(fn, 0)が役に立つことがあるのはなぜですか?
質問
最近、かなり厄介なバグに遭遇しました。
<select>
JavaScriptで動的に この動的に読み込まれる
<select>
はあらかじめ選択された値を持っていました。 IE6 では、すでに選択された
<option>
というのは、時々
<select>
's
selectedIndex
の値は、選択された
<option>
's
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()
?
解決方法は?
質問の中に レースコンディション の間にある。
- ブラウザがドロップダウンリストを初期化しようとし、選択されたインデックスが更新される準備ができたこと、および
- 選択インデックスを設定するコード
あなたのコードは常にこの競争に勝ち続け、ブラウザの準備が整う前にドロップダウンの選択を設定しようとし、バグが表示されることを意味しました。
このレースが存在したのは、JavaScriptが 実行の単一スレッド は、ページレンダリングと共有されています。事実上、JavaScript を実行すると、DOM の更新がブロックされます。
あなたの回避策は
setTimeout(callback, 0)
起動時
setTimeout
をコールバックとし、2番目の引数に0を指定すると、コールバックが実行されるようスケジュールされます。
非同期
タブにフォーカスがあり、JavaScript の実行スレッドがビジー状態でない場合は、10ms 程度の最短時間後になります。
そのため、OPの解決策は、選択したインデックスの設定を10msほど遅らせることでした。これにより、ブラウザはDOMを初期化する機会を得て、バグを修正することができました。
Internet Explorerはどのバージョンも癖のある動作をするので、このような回避策が必要な場合もありました。あるいは、OPのコードベースにおける本物のバグであったかもしれません。
Philip Robertsのトークを参照 イベントループとは一体何なのか? を使うと、より丁寧な説明ができます。
関連
-
vueのプロジェクトでモックを使用する方法を知っていますか?
-
[解決済み】React - TypeError: 未定義のプロパティ 'props' を読み取ることができない。
-
[解決済み] なぜGoogleはJSONレスポンスにwhile(1);を前置するのでしょうか?
-
[解決済み] 私のJavaScriptコードは "No 'Access-Control-Allow-Origin' header is present on requested resource "というエラーを受け取りますが、Postmanはそうならないのはなぜですか?
-
[解決済み] JSONPとは何か、なぜ作られたのか?
-
[解決済み] 配列の反復処理に "for...in "を使用するのは、なぜ良くないのでしょうか?
-
[解決済み] なぜ ++[[]][+[] +[+[]] は "10" という文字列を返すのでしょうか?
-
[解決済み] setTimeout()コールバックにパラメータを渡すにはどうすればよいですか?
-
[解決済み] setTimeoutかsetIntervalか?
-
[解決済み] jQuery テキストエリアでのカーソル位置の設定
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Vue Element-uiは、アイコンを追加するためのツリーコントロールノードを詳細に実装しています。
-
WeChatアプレット用ユニアプリによるグローバルシェアリング
-
HTML+CSS+JavaScriptで簡単な三目並べゲームを作成する。
-
Javascript Bootstrapのグリッドシステム、ナビゲーションバー、ローテーションの説明
-
vueディレクティブv-bindの使用と注意点
-
[解決済み】最大呼び出しスタックサイズ超過エラー
-
[解決済み】TypeError: Router.use() はミドルウェアの関数を要求しているが、Object を取得した。
-
[解決済み】gulp anythingを実行するたびに、アサーションエラーが発生します。- タスク関数を指定する必要があります
-
[解決済み】ExpressJS : res.redirect()が期待通りに動かない?
-
[解決済み】 Uncaught TypeError : undefined のプロパティ 'replace' を読み取れない In Grid