Webアプリっぽいものを作るときは、画像などのリソースを読み込むタイミングが、ページを表示したタイミングと同じではなく、ユーザーがボタンを押したり、何かのイベントが始まったり終わったりなど、 任意のタイミング である場合が多いです。
Flashなどのコンテンツでは、最初にページを開いたタイミングで、0%〜100%までのローディング表示が行われますね。 FlashコンテンツがHTMLベースのコンテンツにどんどん置き換わっている 昨今では、こういったローディングの機能も、HTMLベースのコンテンツに求められてきています。
そうしたときに、画像などのリソースを一旦裏で読み込んでおいて、読み込み終わったものから順に表示したり、あるいはすべて読み込み終わったタイミングで一斉に表示したりといった、いわゆる**「プリローダー」の役割を持ったものが必要**になってきます。
ってことで、プリローダーをいろいろ試してみようと思います。
画像に限らず、「あらかじめ」「ローディング」しておく役割のものを「プリローダー」と呼んでいますが、特に画像に限る必要もないのでは?と思います。
プリローダーの仕組みは、大抵以下のような感じです。
シンプルですね。
まず 1.で、例えば新たに表示したいパーツに使う画像などのリソース一式のURLを、配列などに保存しておきます。もちろんそのプリローダーごとに方法は様々だと思いますが。
続けて 2.で、1ファイル読み込み終わったときの処理を記述します。ここでどんな処理を書けばいいかというと、例えば・・・画像を次々に読み込んで、1ファイル読み込み終わったタイミングで都度HTMLに埋め込んで表示するような、動的な見せ方をするコンテンツなどの処理を書くことができます。
また、全ファイル読み込み終わったときの処理も記述します。画像を一通り読み込み終わってから、まとめて表示したり、すべて読み込み終わった後で何か別の処理をさせたいときなどに使えそうです。
そして最後に 3.で、用意したプリローダーをスタートさせ、実際の読み込みを開始します。
今回は、以下の3つのJavaScriptライブラリ、jQueryプラグインを試してみました。
全部まとめて検証用ページ作って試してみました。 画像数が少ない場合と多い場合とで両方試してみたかったので、とりあえず画像数を10から1000まで切り替えられるようになっています。 ※同じような画像を使っていますが、すべて別ファイルとしてリネームされたものを読み込んでいます。
順に実装の仕方や、試してみた感想などをメモしておきます。
http://thinkpixellab.com/pxloader/
var loader = new PxLoader();
for (var i = 0; i < imageTotal; i++) {
// ここでプリローダーに登録する
var imageFile = new PxLoaderImage(imageURLList[i]);
loader.add(imageFile);
}
loader.addProgressListener(function(event) {
// ここに1ファイル読み込み終わったときの処理を書く
// event.resource.getName() で画像URL参照できる
});
loader.addCompletionListener(function(event) {
// ここに全ファイル読み込み終わったときの処理を書く
});
loader.start();
PxLoader という、jQueryなどの基本ライブラリには依存しないJavaScriptライブラリです。
併せて PxLoaderImage という画像ダウンロード用のプラグインや、PxLoaderSound や PxLoaderVideo などのサウンド、ビデオ用のプラグインもあるようですね。
まずプリローダーのオブジェクトを作り、それに対してプラグインでラッピングした画像URLを登録しています。loader.add でプリローダーに読み込む予定の画像URLを登録しておきます。
loader.addProgressListener で1ファイル読み込み終わった後の処理を、コールバック関数として function 内に書いておきます。このサンプルでは、コールバック関数の引数(ここではevent)に対して、completedCount と totalCount のプロパティで、今の読み込みが完了した画像数と、あらかじめ登録された画像数が参照できるので、これを利用して進捗を表示しています。
var progress = event.completedCount + ' / ' + event.totalCount;
var target = $('<li><img src="' + event.resource.getName() + '"></li>');
target.hide().fadeIn(1000).appendTo(list);
status.text(textLoadStart + ' (' + progress + ')');
また、どのライブラリ、プラグインでも同様の処理をしていますが、読み込み終わったタイミングで li タグで包んでフェードインさせつつ画像を表示させています。
どちらかというと、全体をいっぺんに読み込んで、進捗を表示させるようなものに特化しているような印象を受けます。 Flash などのスペコンで、 途中で切れ目がないような一度に見せるタイプのコンテンツ に向いているかもしれません。
https://github.com/Takazudo/jQuery.ImgLoader
var loader = $.ImgLoader({
// ここでプリローダーに登録する
srcs: imageURLList
});
loader.bind('itemload', function($img) {
// ここに1ファイル読み込み終わったときの処理を書く
// $img が画像のオブジェクトに相当
});
loader.bind('allload', function($img) {
// ここに全ファイル読み込み終わったときの処理を書く
});
loader.load();
jQuery.ImgLoader という、jQuery のプラグイン形式で提供されているプリローダーです。
プリローダーを生成するときに、srcs プロパティに画像URLが入った配列を登録しておき、プリローダーに対して bind で itemload と allload イベントを補足します。loader.load() でプリローダーをスタートさせると、画像が読み込み終わったタイミングでそれぞれ itemload, allload のイベントが発火します。
基本的にjQueryのプラグインとして動作しているため、コールバック関数も 読み込みが完了した画像のjQueryオブジェクトが引数として渡されるため、それをそのまま埋め込みつつ表示にも使ったりできます。また、allload の方も画像のjQueryオブジェクトの配列が返ってくるため、ここで一度に設置することも可能です。
また、srcs に加えて、pipesize や delay プロパティも併せて用意することで、同時に読み込む画像数を制限することが出来ます。(サンプルでは5つに設定してます)
試してみたところの感想ですが、読み込む画像数を増やすと違いがはっきり見えてきますね。pipesize を設定しているせいで同時に読み込む画像数が少なくなり、結果的にすべて読み込むまでの時間は長くなっていますが、その間も特に重たくもなく、スムーズに動かせます。
これは、上記のライブラリとは異なり、その都度読み込みつつ、表示させつつ、使わせつつという、かなりリアルタイムな印象ですね。
https://github.com/farinspace/jquery.imgpreload
// ここでプリローダーに登録する(第1引数)
$.imgpreload(imageURLList, {
each: function() {
// ここに1ファイル読み込み終わったときの処理を書く
// this が画像のオブジェクトに相当
},
all: function() {
// ここに全ファイル読み込み終わったときの処理を書く
}
});
jquery.imgpreload という、こちらも jQuery のプラグインで提供されるプリローダーです。
基本的な機能は他と同じですが、プリローダーに必要な情報を一通り登録したら、それがそのままプリローダー開始となるようです。第1引数に画像URLの配列を登録して、第2引数に1ファイル読み込み終わったときの処理、全ファイル読み込み終わったときの処理をそれぞれ登録します。
他と少し変わっているのが、コールバック関数の引数として画像の情報が返ってきているわけではなく、コールバック関数の this そのものが画像のオブジェクトになっている点ですね。all の方もthis そのものが画像の配列になっていて、一度に画像を設置することも可能です。
こちらも1つ目に紹介したライブラリに近いですが、現在の読み込み数などの情報は、用意されたデモHTMLを見る限り、自前で用意する必要がありそうです。逆にいえば、純粋にプリローダーだけの機能をもったシンプルなプラグインとも言えますね。
元々100ファイルで試していたのですが、あまり大きな違いは見られず、しいて言えば一気に読み込むタイプ、リアルタイムで読み込んでみせるタイプに分類されるのかなーと思っていました。ただ、1000ファイルやそれ以上ファイル数を増やしてみたところ、 読み込み数の制限をかけていないライブラリ、プラグインは、読み込みをしている最中になかなかスクロールしづらい 面があり、かなり違いが表に出てきています。
ファイル数が多く読み込みに時間がかかる場合は、読み込み途中の使い勝手も併せて考慮に入れる必要があると思います。そういった意味で、多少全ての読み込みが完了するまでの時間が遅くなったとしても、 同時読み込み数を制御して、フリーズして使えなくなることを避ける方法 を検討するのも、1つの選択肢ではないでしょうか?
この記事は書かれてから1年以上が経過しており、最新の情報とは異なる可能性があります