SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

CoffeeScriptによるモダンなWebアプリケーション開発

CoffeeScriptベストプラクティス集
ブラウザ向けJavaScript編(2)

CoffeeScriptによるモダンなWebアプリケーション開発 第8回

  • X ポスト
  • このエントリーをはてなブックマークに追加

DOMの準備完了を待つ

 HTMLに含まれるDOM要素の構築が完了しないうちにJavaScriptでDOM要素を参照しようとするとエラーが発生します。これは比較的よくあるミスで、解決方法は至って簡単です。

 実際の例を見てみましょう。リスト5のHTMLをブラウザで読み込むと、変数mainDivnullとなります。これは、<script>内のJavaScriptが実行される時点ではまだdiv要素の構築が完了していないためです。

[リスト5]DOM構築の完了前にスクリプトで取得することはできない
<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <script>
    var mainDiv = document.getElementById('main');
    console.log(mainDiv);  // mainDivはnullとなる
  </script>
</head>
<body>
  <div id="main"></div>
</body>
</html>

 古くから存在する対処法としては、onloadイベント後にJavaScriptが実行されるようにすることでエラーを回避できます。window.onloadに関数を代入すると、ページのDOM構築が完了し、画像やJavaScriptなどの外部ファイルのロードがすべて完了した段階でその関数が実行されます。onloadイベントが発生した時点であればdocument.getElementById()でページ内のすべての要素を取得できます。

[リスト6]onloadイベントで関数を実行する
<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <script>
    // 既存の変数を上書きしないようにスコープを作成して実行する
    (function(){
      // オリジナルのonloadを保存しておく
      var _onload = window.onload;
      window.onload = function() {
        // オリジナルのonloadが存在する場合は実行する
        if (typeof _onload === 'function') {
          _onload.apply(this, arguments);
        }
        var mainDiv = document.getElementById('main');
        console.log(mainDiv);
      };
    })();
  </script>
</head>
<body>
  <div id="main"></div>
</body>
</html>

 しかし、その後jQueryが多くの開発者に使われるようになり、jQueryのready()メソッドを使う方法が一般的になりました。window.onloadは画像を含めたすべてのロードの完了後に実行されるのに対して、jQueryのready()DOM readyイベントと呼ばれ、DOMの構築が完了した時点で関数が実行されます。つまり、画像などのリソースが大量に埋め込まれているページでも、画像の読み込み完了を待たずにDOM readyイベントで関数を実行することができます。DOM readyイベントで実行される関数を登録するには$(document).ready(関数)を実行します(リスト7)。他の関数がすでに登録されていても気にすることなく追加登録できます。

[リスト7]DOM readyイベントで関数を実行する
<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
  <script>
    $(document).ready(function() {
      var mainDiv = document.getElementById('main');
      console.log(mainDiv);
    });
  </script>
</head>
<body>
  <div id="main"></div>
</body>
</html>

 $(document).ready(関数)の代わりに$(関数)と短く書くこともできます(リスト8)。

[リスト8]リスト7のもう一つの書き方
<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
  <script>
    $(function() {
      var mainDiv = document.getElementById('main');
      console.log(mainDiv);
    });
  </script>
</head>
<body>
  <div id="main"></div>
</body>
</html>

 他の手法としては、<script></body>の直前に置くことで、実行中の<script>より前の部分のDOM構築が完了していることを前提に処理を進めることができます(リスト9)。ただしdocument.write()を使っているJavaScriptコードの実行箇所を移動すると問題が生じるため、そのようなJavaScriptにはこの方法は使えません。jQueryのready()は汎用的に使うことができ、ライブラリとして公開する場合など実際にどのタイミングで読み込まれるかわからない場合などに便利です。これら2つの手法を組み合わせてready()</body>の直前に置いても問題ありません。

[リスト9]JavaScriptを</body>の直前に移動する
<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
</head>
<body>
  <div id="main"></div>
  <script>
    var mainDiv = document.getElementById('main');
    console.log(mainDiv);
  </script>
</body>
</html>

JavaScriptとCSSの最適な読み込み順序

 一般的に、CSSは<head>内で読み込み、JavaScriptは<body>の最後、つまり</body>の直前で読み込むのがよいとされています。描画が始まってからCSSを読み込むと、CSSが適用されていないページが一瞬表示されてしまいます。また<head>内や<body>の途中で外部JavaScriptを読み込むとそのロードが完了するまでそれ以降の描画は行われません。CSSを読み込むタグは<head>内にまとめておき、またJavaScriptを読み込むタグはbodyの描画前に実行しなければならないものやdocument.write()を使用しているもの以外は</body>の直前に置くとよいでしょう。

 jQueryなど必ずしもページ描画前にロードする必要のないライブラリを</body>の直前で読み込むようにするだけでユーザーから見た体感速度が向上することもあります。

スクリプトローダーで高速に読み込む

 JavaScriptの読み込みを高速化する手段としてスクリプトローダーを使うこともできます。スクリプトローダーとは、JavaScriptをロードするためのJavaScriptライブラリです。

 高速なスクリプトローダーの一つにLABjs(MITライセンス)があります。LABjsを使うと、スクリプトの読み込みが様々なテクニックで高速化されます。LABjsで外部JavaScriptをロードする処理をすべて<head>内に入れておいても、ページの描画を中断させることなくスクリプトのロードを同時並行で行うことができます。

LABjsの使い方

 LABjsのWebサイトからファイルをダウンロードし、LAB.min.jsを自分のサイトに設置します。

 LABjsは通常、リスト10のようにHTMLに埋め込んで使います。このブロックは</body>の直前に入れても構いませんし、<head>内に入れても構いません。CoffeeScriptで外部スクリプトとして書くこともできますが、HTMLに埋め込んだ方が読み込みが高速になります。あるいはLAB.min.jsと自分のJavaScriptを結合させて外部ファイルにして読み込むのもよいでしょう。

[リスト10]LABjsで外部JavaScriptをロードする
<script src="js/LAB.src.js"></script>
<script>
  $LAB
  .script('https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js')
  .script('js/underscore-min.js').wait()
  .script('js/myscript.js');
</script>

 外部JavaScriptを読み込むには$LAB.script()を呼びます。

$LAB.script(URL);

 LABjsのメソッドはドットを続けて書いていくことができます。このような鎖状の書き方を一般的にメソッドチェーンと呼びます。

$LAB.script('script1.js').script('script2.js').script('script3.js');

 $LAB.wait()をチェーンの中に置くと、それ以前のスクリプトの実行完了を待ってから次のスクリプトを実行します。以下の例では、script1.jsとscript2.jsの実行が完了してからscript3.jsが実行されます。

$LAB
.script('script1.js')
.script('script2.js').wait()
.script('script3.js');

 例えばjQueryに依存しているライブラリはjQueryより後に実行する必要があるため、jQueryの後に$LAB.wait()を挟みます。$LAB.wait()を入れてもスクリプトのダウンロード自体は同時並行で行われ実行順序だけが制御されるので、時間の無駄は最小限に抑えることができます。

 また$LAB.wait()には引数として関数を渡すことができ、それ以前のスクリプトの実行が完了した時点で任意の関数を実行できます。

$LAB
.script('script1.js')
.script('script2.js')
.wait(function() {
  console.log("script1と2の実行が完了");
})
.script('script3.js');

 LABjsはIE6以上など現在使われているほぼ全てのブラウザで動作します。

 通常は</body>の直前に<script>を置くだけでも十分ですが、特にスピードが重視される場面ではLABjsを使うとさらに高速化できる場合があります。ただし、LABjsの読み込みや実行にもわずかながらオーバーヘッドが発生するため、どちらが高速か実験してから使うとよいでしょう。

次のページ
パフォーマンス向上のためのテクニック

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
CoffeeScriptによるモダンなWebアプリケーション開発連載記事一覧

もっと読む

この記事の著者

飯塚 直(イイヅカ ナオ)

1984年東京都生まれ。 高校時代に趣味でPerlやJavaを使ってプログラミングを始める。 慶応大学湘南藤沢キャンパス卒業後、共同通信社にてニュースサイトの開発などを担当。 その後、面白法人カヤックにてソーシャルゲームの開発などを手がける。 2012年現在、カヤックを退社し個人として活動し...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6536 2012/05/11 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング