Lazy Load Plugin for jQuery

後から読み込んでよ

うちのサービスはほぼデータを表示・編集する事が主なのだが、その一つ一つのデータは必ず画像を含むわけです。(まあ、弊社のサービス内容見れば何の画像かは明らかですが。)

その画像はまあ3〜4KBぐらいなんですが、それでもデフォルトで100件とかの表示になると結構な分量です。しかもサービスの特性上できるだけキャッシュさせたくないので、毎回URLは変わるのでブラウザのキャッシュも期待できません。

そんなこんなでメインのページでさえ結構な読み込み時間・サイズになってしまうわけです。ちなみに100件表示だとページ全体で1.5Mぐらい。。

で、目をつけたのがLazy Load Pluginというわけですね。まあ、何かのついでに手軽にできないかなーぐらいで。

さっそく使ってみる

このプラグイン自体は皆さん使われているようで、軽く調べただけでも相当数の使用記事が見つかりました。
なので詳細は省きますが一応。

基本的な使い方

全体にはかけたくなかったので、検索結果の対象画像のみに絞った状態で適用させています。placeholderは読み込み前の画像です。

<script type="text/javascript" src="./js/jquery.lazyload.mini.js"></script>

<script type="text/javascript">
// <![CDATA[
  $(function() {
    $('.search_results img.img-mid').lazyload({ 
      placeholder : "image/nowLoading.gif"
    });
  });
// ]]>
</script>

まずはFireFox.....ダメですね。

このプラグインはimgタグのsrcを一旦originalっていう別の属性に逃がして、appearイベントの時にoriginalからsrcに戻すっていう単純な事をしているんですが、FireFoxみたいなブラウザだとリクエストを飛ばすのが早いのかsrcをoriginalに逃がす前にもうリクエストしちゃってるみたいなんです。。Firebugをワクワクしながら見てたら、無駄に2回リクエスト飛ばしてるだけじゃねぇかと絶望しました。。

ではどうするか

簡単ですね、最初からoriginalに逃がしておいて、srcにはplaceholderに指定する画像を最初から指定しておけばよいわけですよ。

ASP.NETですとこんな感じですかね。

img.ImageUrl = "image/nowloading.gif";
img.Attributes["original"] = "本当に指定したい画像のurl";
さてどうなるか

おお、いい感じに初回リクエスト数が減っています!(それでも多いな。。)

あれ、先頭の方の画像が読み込まれない

なんでしょうか、最初から表示されるはずの画像が読み込まれませんね。
なんかよくわからないですがソースを見る限りでは、ロード済フラグが済状態になってしまていそうですね。

どうしようか

とりあえず先程の対応で最初からプレースホルダー画像を指定したので、プレースホルダーに差し替え関連の処理は要らないので削ってしまいましょう。その時についでにロードフラグを必ず未ロード状態にしてみましょうか。
はい、こんな感じでコメントアウト

this.each(function() {
  var self = this;

  /* Save original only if it is not defined in HTML. */
  //if (undefined == $(self).attr("original")) {
  //  $(self).attr("original", $(self).attr("src"));     
  //}

  //if ("scroll" != settings.event || 
  //     undefined == $(self).attr("src") || 
  //     settings.placeholder == $(self).attr("src") || 
  //    ($.abovethetop(self, settings) ||
  //     $.leftofbegin(self, settings) || 
  //     $.belowthefold(self, settings) || 
  //     $.rightoffold(self, settings) )) {
  //                        
  //  if (settings.placeholder) {
  //    $(self).attr("src", settings.placeholder);      
  //  } else {
  //    $(self).removeAttr("src");
  //  }
    self.loaded = false;
  //} else {
  //  self.loaded = true;
  //}

  /* When appear is triggered load original image. */
  $(self).one("appear", function() {
    if (!this.loaded) {
      $("<img />")
        .bind("load", function() {
          $(self)
            .hide()
            .attr("src", $(self).attr("original"))
            [settings.effect](settings.effectspeed);
          self.loaded = true;
        })
        .attr("src", $(self).attr("original"));
    };
  });
  /* When wanted event is triggered load original image */
  /* by triggering appear.                              */
  if ("scroll" != settings.event) {
    $(self).bind(settings.event, function(event) {
      if (!self.loaded) {
        $(self).trigger("appear");
      }
    });
  }
});
さてどうなるか

なんか上手くいきました。ええんかいという気もしますが、それほど間違っている事をしているようにも見えないので問題が出るまではこのままにしておきましょうかね。

ああ、やっぱりIEはだめなのね。。

この2010年も後半に入った今でさえ、弊社のユーザーは圧倒的にIE6が多いです。そして、やっぱりIE6だとだめなんですね。。
まあ、ダメというよりは極端に遅くなります。これは逆に使わない方が良さそう。。

まあ、ケースバイケースで使えればいいかな。

IE6では絶望的な劣化をしてしまったものの、FireFox, Chromeでは明らかに早くなったし、使わないってのは惜しい気がする。
上手く妥協点を見つけながら導入していく事にしやしょう。