2009年8月21日金曜日

[jQuery] 画像をあらかじめ読み込む方法

Javascriptで動的に画像要素を生成する時の話です。

jQuery Gallery Pluginを作っててちょっとハマったのは、「画像をいつ読み込むか & どう読み込むか」という点でした。

画像ギャラリーなどのように、動的に画像要素を生成して、大きめの画像を一枚ずつ表示させようとすると、読み込みの遅延に悩まされます。

画像の容量が大きければ大きいほど画像の読み込みに時間がかかって、
A -> B -> C
と滑らかに切り替えたいのに、
A -> (画像の読み込み) -> B -> (画像の読み込み) -> C
といった感じに遅延が発生してしまいます。

この点を解決する手段として、以下のようなやり方が考えられます。

メジャーなブラウザは画像などの静的ファイルをキャッシュしてくれるので、一度読み込んだ画像を次に表示する時は滑らかになります。

この機能を利用して、ページをロードした時点で画像をまとめて読み込んでおくと、いざ画像を表示しようとする時に遅延が発生せずスムーズに切り替えを行うことができるようになります。

ようするに、Aの画像を表示する前に、ユーザーには見せない形でB,Cの画像も読み込んでおくという方法です。


ただ、これを実装するにはどうすればいいの?というのが疑問だったので、とりあえずは自分なりに実装してリリースしてみましたが、stackoverflowを眺めていたらまさしくこれに関する回答があったので感動しました。

Preloading images with jQuery
http://stackoverflow.com/questions/476679/preloading-images-with-jquery

function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
$('<img/>')[0].src = this;
// Alternatively you could use:
// (new Image()).src = this;
});
}

// Usage:

preload([
'img/imageName.jpg',
'img/anotherOne.jpg',
'img/blahblahblah.jpg'
]);

ちなみにjQuery Gallery Pluginでは以下のように記述しています。
var preLoad = function (url) {
jQuery('<img />')
.hide()
.attr('src', url)
.appendTo(document.body)
.load(function () { jQuery(this).remove(); })
.error(function () { jQuery(this).remove(); });
}

大きな違いはdocument.bodyにappendしているかしていないか、です。

bodyにappendしないと画像を読み込むことはできないと思い込んでいたのですが、そうではないらしく
firebugで確認したところ
jQuery('<img />').attr('src', url);

これだけで画像の読み込みが始まりました。

無駄なappendを省いたので要素を削除する処理も必要ありません。

使いどころは限られているかもしれませんが使えるテクニックだと思います。

ブラウザによって挙動が変わったりしたら怖いのですが。。。

1 件のコメント:

Senna さんのコメント...

丁度探していた情報だったので、めっちゃ助かりました。