WebアプリケーションではJavaScriptの読み込み位置をHTMLの最後に行うことで、
JavaScript読み込み位置における起動時間パフォーマンス差
PhoneGapに付属しているターミナル/コマンドプロンプト用のcreateコマンドで作成したプロジェクトでは、
外部JavaScriptファイルの読み込みをHTMLの最後に行うことで、
PhoneGapアプリケーションにおける、
- load
 - ドキュメントの読み込みがすべて完了した時点で発火
(Window)  - DOMContentLoaded
 - DOMの構築が完了した時点で発火
(Document)  - onDOMContentLoaded
 - Cordova内部のイベント。Webページの読み込み・
パースが完了した時点で発火  - onNativeReady
 - Cordova内部のイベント。Cordovaのネイティブ側の使用準備が整った段階で発火
 - onCordovaReady
 - Cordova内部のイベント。Cordovaで提供されるJavaScriptオブジェクトがすべて作成された時点で発火
 - onCordovaInfoReady
 - Cordova内部のイベント。Device APIでデバイス情報を取得できるようになった段階で発火
 - onCordovaConnectionReady
 - Cordova内部のイベント。Connection APIで回線情報を取得できるようになった段階で発火
 - onDeviceReady
 - Cordovaの機能が利用できるようになった段階で発火
 
Cordova内部で利用されているイベントは、
- JavaScriptのロード位置を<head>内末尾にした場合
 - ループ処理をloadイベント後に行った場合
 - ループ処理をDOMContentLoadedイベント後に行った場合
 - ループ処理をdevicereadyイベント後に行った場合
 - リモートホストのJavaScriptファイルを<script>タグで読み込んだ場合
 - リモートホストのJavaScriptファイルをdevicereadyイベント後に読み込んだ場合
 
- JavaScriptのロード位置を<body>内末尾にした場合
 - ループ処理をloadイベント後に行った場合
 - ループ処理をDOMContentLoadedイベント後に行った場合
 - ループ処理をdevicereadyイベント後に行った場合
 - リモートホストのJavaScriptファイルを<script>タグで読み込んだ場合
 - リモートホストのJavaScriptファイルをdevicereadyイベント後に読み込んだ場合
 
なお、
- デバイス: iPad 2
 - Cordova: 2.
1.0  
計測に使用したファイル・計測結果 
ベースとなるHTMLファイル/JavaScriptの読み込み/ループのコードは次のとおりです。
<script type="text/javascript">
var time = Number(new Date());
</script>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
        <title></title>
    </head>
    <body>
        <div class="app">
            <ul>
                <li id="onload"></li>
                <li id="domloaded"></li>
                <li id="deviceready"></li>
                <li id="heavyjsloaddone"></li>
                <li id="loopjsloaddone"></li>
            </ul>
        </div>
    </body>
</html>
<script type="text/javascript" src="cordova-2.1.0.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript">
    app.initialize();
</script>
var app = {
    initialize: function() {
        this.bindEvents();
    },
    bindEvents: function() {
        window.addEventListener('load', this.onLoad, false);
        document.addEventListener('DOMContentLoaded', this.domContentLoaded, false);
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    onLoad: function() {
        document.getElementById('onload').textContent = 'onload: ' + ( Number(new Date()) - time );
    },
    domContentLoaded: function() {
        document.getElementById('domloaded').textContent = 'domContentLoaded: ' + ( Number(new Date()) - time );
    },
    onDeviceReady: function() {
        document.getElementById('deviceready').textContent = 'deviceready: ' + ( Number(new Date()) - time );
    }
};
function loop()
{
    val = 0;
    for ( i = 1; i<1000000; i++) 
    {
        val++;
    }
    document.getElementById('loopjsloaddone').textContent = 'loopjsloaddone: ' + ( Number(new Date()) - time );
}
リモートホストに配置するJavaScriptファイルサイズは、
/usr/local/www/nginx# ls -l | grep js -rw-r--r-- 1 root wheel 2060214 Oct 21 21:28 heavy-library.js
上記の条件をもとにそれぞれ5回試行し、
| 実施内容 | load | DOMContentLoaded | deviceready | ループ終了/JSロード完了 | 
|---|---|---|---|---|
| A. ループ処理をloadイベント後に行った場合 | 44 | 43 | 728 | 595 | 
| B. ループ処理をDOMContentLoadedイベント後に行った場合 | 597 | 44 | 730 | 596 | 
| C. ループ処理をdevicereadyイベント後に行った場合 | 53 | 44 | 172 | 724 | 
| D. リモートホストのJavaScriptファイルを<script>タグで読み込んだ場合 | 1677 | 1678 | 1816 | 1677 | 
| E. リモートホストのJavaScriptファイルをdevicereadyイベント後に読み込んだ場合 | 43 | 42 | 171 | 1521 | 
| 実施内容 | load | DOMContentLoaded | deviceready | ループ終了/JSロード完了 | 
|---|---|---|---|---|
| A'. ループ処理をloadイベント後に行った場合 | 44 | 43 | 729 | 595 | 
| B'. ループ処理をDOMContentLoadedイベント後に行った場合 | 598 | 44 | 731 | 597 | 
| C'. ループ処理をdevicereadyイベント後に行った場合 | 44 | 43 | 173 | 725 | 
| D'. リモートホストのJavaScriptファイルを<script>タグで読み込んだ場合 | 1598 | 1597 | 1732 | 1598 | 
| E'. リモートホストのJavaScriptファイルをdevicereadyイベント後に読み込んだ場合 | 46 | 45 | 175 | 1658 | 
計測結果からわかること
筆者が行った環境では、
読み込み位置におけるパフォーマンス差を考慮しない場合、
- ループ処理をdevicereadyイベント後に行った場合
 - リモートホストのJavaScriptファイルをdevicereadyイベント後に読み込んだ場合
 
の2つです。これは、
| 実施内容 | deviceready | ループ終了/JSロード完了 | 
|---|---|---|
| A. ループ処理をloadイベント後に行った場合 | 728 | 595 | 
| B. ループ処理をDOMContentLoadedイベント後に行った場合 | 730 | 596 | 
| C. ループ処理をdevicereadyイベント後に行った場合 | 172 | 724 | 
| D. リモートホストのJavaScriptファイルを<script>タグで読み込んだ場合 | 1816 | 1677 | 
| E. リモートホストのJavaScriptファイルをdevicereadyイベント後に読み込んだ場合 | 171 | 1521 | 
これらの結果から、
devicereadyイベントが発火する前に、
検証の結果から、
- devicereadyイベント前に負荷の大きい処理や、
リモートホスト上のサイズの大きいファイルをロードさせない。これらはすべて、 devicereadyイベント発火後に行わせるように  - 可能な限り、
ファイルはすべてローカルに配置する  - リモートホスト上のファイルを使用する場合、
リソースの圧縮やWebサーバのgzip圧縮転送を利用して転送量を少なくする  
外部WebサービスのAPIなどを利用している場合、
var script = document.createElement('script');
script.src = '(読み込みたいJavaScriptファイルのURI)';
script.type = 'text/javascript';
document.getElementsByTagName('head').item(0).appendChild(script);
規模の大きいPhoneGapアプリケーションを開発していて起動速度が当初に比べて遅くなってきていると感じた場合、
