JavaScriptの性能について整理しておく
JavaScriptのチューニングの実践を通して学んだことを整理しておく。
クライアントJavaScriptの高速化の肝はDOMアクセスと変数アクセスにある。
特にDOMアクセスのコストは格段に高いため、一番のチューニングポイントになる。
- DOMアクセス
- DOMアクセスの削減
- DOMアクセスのセレクタの効率化
- 変数アクセス
以下に詳細は記述するが、全てに通ずる重要な一つの考えは、「不要な探索をさせない」ということだ。
DOMアクセス
DOMアクセスのタイミング
- DOM要素の取得
- 取得したDOM要素への操作
上記 2. がくせ者で、取得したDOM要素のプロパティにアクセスするたびに、DOMに対して探索が再実行されてしまう。
つまり・・・下記の処理を記述した場合、処理Aと処理Bのコストは同じということか・・・??←検証宿題
var id1 = $('#id1');
id1.val(); // 処理A
$('#id1').val(); // 処理B
たしかに、 #id1 の val はいつ変化するかわからないため、毎回DOMを見に行く必要があるのは然りだ。
DOMアクセスの削減
複数回参照する値については、ローカル変数にキャッシュすることで無駄なアクセスを回避する。
DOMアクセスのセレクタの効率化
前回の日記「CSSの適用について、予想外の事実を知った - oknknicの日記」を参照のこと。
変数アクセス
変数へのアクセス時間は、対象の変数がスコープチェーンのどこに位置するかと、その変数の格納場所に依存する。
いずれの場合も、複数回アクセスする場合は、ローカル変数にキャッシュすることで性能改善が可能である。
スコープチェーン
スコープは、以下の順でスタックに積まれていく。各スコープについて、そのスコープから下方向にあるスタック列をスコープチェーンと呼ぶ。
- 【ページロード時】グローバルスコープ生成
- 【関数呼び出し時*】スコープ生成
- 【関数内でwithあるいはcatchを実行時*】スコープ生成
また関数には、それが定義された際のスコープチェーンにアクセスするため、内部プロパティ Scope に定義時のスコープチェーンが設定されている。
スコープアクセスの性能
ローカル変数への読み書きは、識別子の解決のためにスコープチェーンを辿る必要がないため、格段に高速である。
逆に、グローバルオブジェクトへのアクセスは最も低速である。
ただし、性能影響の規模は、下記検証サイトでも確認できるように、非常に小さいものである。
補足:性能改善の限界を越えたいとき
越えられない壁を越えなければならないときは、 setTimeout による遅延実行を検討する。
シングルスレッドであるJavaScriptは、実行するコードをキューで管理している。 setTimeout 関数を使って関数を実行すると、その関数の処理を現在実行中の処理の一部とするのではなく、別の処理としてエンキューすることができる。
このように処理の実行を分割することで、ユーザ処理を挟み込む間ができるため、ユーザ視点では性能が改善されたと感じる。
参考文献
続・ハイパフォーマンスWebサイト ―ウェブ高速化のベストプラクティス
- 作者: Steve Souders,武舎広幸,福地太郎,武舎るみ
- 出版社/メーカー: オライリージャパン
- 発売日: 2010/04/10
- メディア: 大型本
- 購入: 20人 クリック: 351回
- この商品を含むブログ (29件) を見る