アプリケーションキャッシュを試してみる

2回目以降の起動が速くなるということで、HTML5のアプリケーションキャッシュを試してみた。けど、結論から言うとあまり実感は得られなかった。とりあえず、やったことをメモっておく。
#追記:ちゃんとやったら結構効果はあった。特に画像をキャッシュするとより効果的。

描画、特に各 li 要素の背景に設定している画像の読み込みが遅そうだったのでそれをキャッシュする方向でチャレンジ。

マニフェストファイルを用意する

どのファイルをキャッシュするかを設定するファイルが必要とのこと。cache.manifest というファイルを index.jsp と同じディレクトリに作成し、以下のような記述をする。

  • 「CACHE:」の下にキャッシュしたいファイル名を記述
  • 「NETWORK:」の下にキャッシュしないファイル名を記述する。キャッシュしたいファイルだけじゃなくて、ちゃんとこっちも書いておかないとダメみたい。
  • 「#version」はコメント。有っても無くてもよいが、キャッシュ対象のファイルを更新した場合はマニフェストファイルも変更しておかないといけない。普通は version の番号を変えることで実現しているとのこと。
CACHE MANIFEST
# version 1.2
CACHE:
/css/todo.css
/css/ui-lightness/jquery-ui-1.8.7.custom.css
/img/todo/doing_gra.jpg
/img/todo/waiting_gra.jpg
/img/todo/todo_h_gra.jpg
/img/todo/todo_gra.jpg
/img/todo/todo_l_gra.jpg
/img/todo/done_gra.jpg

NETWORK:
/js/jquery-1.4.4.min.js
/js/jquery-ui-1.8.7.custom.min.js
/js/todo.js

MIMEの設定をする

マニフェストファイルを「text/cache-manifest」というタイプで送信してあげる必要があり、その設定を web.xml に追加する。

  • web.xmlmime-mapping タグを追加する。拡張子を manifest とした場合は extension タグの要素と合わせる。
<?xml version="1.0" encoding="utf-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
                    :
    <mime-mapping>
        <extension>manifest</extension>
        <mime-type>text/cache-manifest</mime-type>
    </mime-mapping>
</web-app>

htmlでマニフェストファイルを読み込む

  • キャッシュしたい html で以下のように記述。
<html manifest="cache.manifest">

上記変更を行い、GAEにデプロイする。キャッシュされているかどうかは GoogleChromeでは「デベロッパーツール」を開いて「Storage」タブの「APPLICATION CACHE」を参照する。XXX.jpg とかキャッシュされているのがわかる。

でも実際に iPad 上でリロードしてみたけれど、表示が早くなっている実感は得られなかった。何か他の問題もあるのかもしれない。

2011/1/5 追記:たしかに起動は速くなったが、キャッシュされすぎる

上記方法で改めてみてみるとたしかに画像などのキャッシュにより起動速度は改善されていた。しかし、マニフェストに記述したファイル以外にも初期の html 自体も暗黙的にキャッシュされてしまうため、GAEにより動的に生成した html がそのまま残ってしまう。それにより、画面に変更を加えた後に再描画しても変更前の状態に戻ってしまう現象が発生する。
特に今回題材としているTodoListの場合、マウスでタスクをドラッグして状態を変えたとしても、再読込した瞬間に変更前に戻ってしまう。これを回避するには初期html をキャッシュさせなくする必要がありそうだが、そんな方法はあるのだろうか。

視点を変えて初期htmlには動的なデータを含めないという方法もありそう。最初は固定htmlを表示しておいて読み込み開始イベントで必要なデータを Ajaxで取りに行く。起動時間も速く見えるだろうしこちらの方が現実的かもしれない。今度試してみよう。

iPad 固有の問題

iPad上のデスクトップ上に貼りつけたショートカットから起動した場合、タスクのドラッグをした後のレスポンスの値が正しくないことがわかった。ドラッグ時の値によってDBの値が変わっているのでリクエストはサーバに届いてはいるのだろうが、レスポンスの値が上手く受け取れていないようだ。

同じiPadでも普通に Safari で起動した場合とデスクトップショートカットから起動した場合で挙動が異なるのが不思議だ。内部的にはどうなっているんだろう。Cookieは同じものを使っていそうだが。

2011/1/31 さらに追記:初期表示データは動的コンテンツを排除する

DBから読み込んで表示する初期データは最初から初期HTMLに配置してしまうと前述しているようにキャッシュされてしまって変更が上手く反映されない。
そこで、初期HTMLはあくまでも静的データのみ表示して、初期化イベントで Ajax を使ってデータを読み込む様にしたら不必要にキャッシュされることはなくなった。画像のキャッシュも効くし、jsや css も問題なくキャッシュされている。iPadでも正常に動く。さらに最初の画面が出るまでの時間も早くなるので待たされ感も減り、ユーザビリティも上がる。

結論

いろいろやってみて、アプリケーションキャッシュを動的ページに適用する場合の注意点は以下

  • 初期HTMLに動的データを含めてはいけない
  • 初期ロード処理にて、Ajaxを用いて動的データをサーバに取りに行くようにする
  • データ取得中は表示する箇所にロード中 gif を置くなどして読み込み中をアピールする
  • 画像だけでなく、JavaScriptCSS などもキャッシュ可能。全てキャッシュでいいかも
  • キャッシュ対象のファイルを変更した場合はマニュフェストの ver を変更してデプロイ