Corredor

ウェブ、プログラミングの勉強メモ。

IE11 で大量のテキストボックスを一括で非活性にする処理が重すぎる

IE11 は他のブラウザと比べても element.disabled = true; とかする処理が重たい。

ワケあって、テーブルの中に1行20個、150行程度のテキストボックスがあって、これらを一括で非活性にしたり、戻したりしなくてはいけなくなった。何も考えず document.getElementsByTagName("input") で取ってきた要素をループで回して element.disabled = true; とかしてみたら、IE11 ではかなり時間がかかってしまった。PC のスペックによっては2分ぐらい固まってしまった。

ちなみに同じ処理でも Firefox や Chrome だと高速、特に Chrome は 30ms かからない。IE11 だけ、とんでもなく遅いのだ。setInterval() で非同期処理?とかさせてみたけどうまく改善されず。見た目のもっさり感がなくなっただけで処理の完了まではやはり時間がかかる。

そこで、IE11 でのみ有効なチューニングを調べてみたところ、element.cloneNode() で非活性にしたいテキストボックスを複製し、複製したテキストボックスを非活性にしてから element.replaceChild() で要素を差し替える、という方法を見つけた。どうやら IE11 では、テーブル内に input 要素が大量にある状態で disabled 操作を行う場合に、とても遅くなるようだ。

チェックボックスやラジオボタンは checked の状態が引き継がれなかったりとバグがあるらしいので、type="text" 以外は通常どおり element.disabled で操作する必要がある。本当に使う時は type 属性をチェックしたりすると良いだろう。実務ではその画面の作りに最適化させ、テキストボックスの要素のみ replaceChild を行う関数を作っておいた。

以下に、CodePen でサンプルを作ってみたので、操作してみてほしい。CodePen のサイト上で Console を見れば実行時間も見られる。

See the Pen Disabled In Bulk by Neos21 (@Neos21) on CodePen.

removeAttribute("disabled"); は上記の参考サイトには出てきていないけど、Edge モードの IE11 や Firefox などでは setAttribute("disabled", false); だと活性化させられなかったので追加した。実務では IE8 互換で動いているので、removeAttribute() は要らず、setAttribute("disabled", false); が効いてくれている。どうせ社内のショボいシステムなのでゴリッゴリに環境依存したやり方でいいわ。

replaceChild() する要素を style.display = "none"; で非表示にしたりだとか、テーブル全体を非表示にしてみたりすると、もう少し速くなるらしい。体感できるほどではなかったけど入れてみた。

table-layout:fixed; がレンダリングに影響を与えるか?と思ったけど、試してみた限り auto (未指定) でも fixed でも、disabled 操作には関係なかった。

これだけあれやこれややったけど、Firefox や Chrome は、何も考えず element.disabled で操作するのが一番速かった。どうせ IE でしか閲覧しない社内のショボいシステムなので (ry

もし IE でもっと速くなる方法をご存知でしたら教えてください。