Javascriptで画像をどのようにキャッシュしますか


83

私の友人と私は、将来それらをより速く表示するために特定の画像をキャッシュしたいウェブサイトに取り組んでいます。私は2つの主な質問があります:

  1. 画像をどのようにキャッシュしますか?
  2. キャッシュされた画像をどのように使用しますか?(そして、確認のために、画像がページAにキャッシュされている場合、キャッシュから呼び出してページBで使用することは可能ですよね?)

また、キャッシュされたバージョンの画像の有効期限を設定することはできますか?

これをさらに説明する例および/またはページへのリンクが含まれていれば幸いです。

生のJavascriptまたはjQueryバージョンのいずれかを使用しても問題ありません。


12
あなたはしません。ブラウザはそうします。
とがった2012

ブラウザは画像を自動的にキャッシュしますか?
Logan Besecker 2012

8
@Logan:はい、サーバーが必要なヘッダーを送信してブラウザに安全にキャッシュできることを通知すれば、ブラウザは画像を自動的にキャッシュします。(これらのヘッダーは、質問の一部である有効期限をブラウザーに通知する場合もあります。)
icktoofay 2012

ブラウザが必要なヘッダーを送信していることを確認するにはどうすればよいですか?
Logan Besecker 2012

1
@LoganBeseckerブラウザの開発ツールの[ネットワーク]セクションで応答ヘッダーを確認できます。
jlaceda 2012

回答:


131

画像がブラウザに何らかの方法で読み込まれると、その画像はブラウザのキャッシュに保存され、その画像が現在のページにあるか他のページにあるかに関係なく、次に使用されるときにはるかに高速に読み込まれます。ブラウザのキャッシュから期限切れになる前に使用されます。

したがって、画像をプリキャッシュするには、画像をブラウザにロードするだけです。大量の画像をプリキャッシュする場合は、JavaScriptを使用して行うのが一般的に最適です。これは、JavaScriptから実行した場合、通常、ページの読み込みが妨げられないためです。あなたはこのようにそれを行うことができます:

function preloadImages(array) {
    if (!preloadImages.list) {
        preloadImages.list = [];
    }
    var list = preloadImages.list;
    for (var i = 0; i < array.length; i++) {
        var img = new Image();
        img.onload = function() {
            var index = list.indexOf(this);
            if (index !== -1) {
                // remove image from the array once it's loaded
                // for memory consumption reasons
                list.splice(index, 1);
            }
        }
        list.push(img);
        img.src = array[i];
    }
}

preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"]);

この関数は何度でも呼び出すことができ、毎回、プリキャッシュに画像を追加するだけです。

このようにjavascriptを介して画像がプリロードされると、ブラウザは画像をキャッシュに保存し、他の場所(Webページ内)で通常のURLを参照するだけで、ブラウザはそのURLをキャッシュから取得します。通信網。

最終的には、ブラウザのキャッシュがいっぱいになり、しばらく使用されていない最も古いものが破棄される可能性があります。したがって、最終的には、画像はキャッシュからフラッシュされますが、しばらくの間そこにとどまる必要があります(キャッシュの大きさや他のブラウジングの量によって異なります)。画像が実際に再度プリロードされるか、Webページで使用されるたびに、ブラウザキャッシュ内の画像の位置が自動的に更新されるため、画像がキャッシュからフラッシュされる可能性は低くなります。

ブラウザのキャッシュはクロスページであるため、ブラウザに読み込まれたすべてのページで機能します。したがって、サイトの1つの場所でプリキャッシュを行うと、ブラウザのキャッシュがサイトの他のすべてのページで機能します。


上記のようにプリキャッシングする場合、画像は非同期で読み込まれるため、ページの読み込みや表示が妨げられることはありません。ただし、ページに独自の画像が多数ある場合、これらのプリキャッシュ画像は、帯域幅やページに表示されている画像との接続をめぐって競合する可能性があります。通常、これは目立った問題ではありませんが、接続速度が遅い場合、このプリキャッシングによってメインページの読み込みが遅くなる可能性があります。プリロード画像が最後にロードされても問題がない場合は、他のすべてのページリソースがすでにロードされるまで、プリロードの開始を待機するバージョンの関数を使用できます。

function preloadImages(array, waitForOtherResources, timeout) {
    var loaded = false, list = preloadImages.list, imgs = array.slice(0), t = timeout || 15*1000, timer;
    if (!preloadImages.list) {
        preloadImages.list = [];
    }
    if (!waitForOtherResources || document.readyState === 'complete') {
        loadNow();
    } else {
        window.addEventListener("load", function() {
            clearTimeout(timer);
            loadNow();
        });
        // in case window.addEventListener doesn't get called (sometimes some resource gets stuck)
        // then preload the images anyway after some timeout time
        timer = setTimeout(loadNow, t);
    }

    function loadNow() {
        if (!loaded) {
            loaded = true;
            for (var i = 0; i < imgs.length; i++) {
                var img = new Image();
                img.onload = img.onerror = img.onabort = function() {
                    var index = list.indexOf(this);
                    if (index !== -1) {
                        // remove image from the array once it's loaded
                        // for memory consumption reasons
                        list.splice(index, 1);
                    }
                }
                list.push(img);
                img.src = imgs[i];
            }
        }
    }
}

preloadImages(["url1.jpg", "url2.jpg", "url3.jpg"], true);
preloadImages(["url99.jpg", "url98.jpg"], true);

この例では、URLごとに新しいImageオブジェクトを作成しています。ループの外側でimg変数を設定し、srcを更新するだけの場合、同じ効果があり、リソースが削減されます
cadlac 2014

1
@ cadlac-しかし、ブラウザが実際に各画像をダウンロードしてキャッシュすることを確認するには、新しい.srcプロパティを設定する前に、1つの画像のダウンロードが完了するまで待つ必要があります。そうしないと、ブラウザが以前のダウンロードを停止して、正常にキャッシュできなくなる可能性があります。
jfriend00 2014

新しいバージョンのブラウザでも待たずに動作するようですが、良い点があります。互換性を確認するには、いくつかの古いブラウザで試してみる必要があります:)
cadlac 2014

@ cadlac-必要ありません。Image()画像の読み込みが完了したときにリストから要素を削除するようにコードを更新しました。画像の読み込みが完了するまで待つ方が安全です。
jfriend00 2014

1
他のドキュメントリソースが読み込まれるまで待機する別のバージョンのスクリプトを追加して、画像のプリロードが表示されているページリソースの読み込みと帯域幅を競合しないようにしました。
jfriend00 2015

13

@Pointyがjavascriptで画像をキャッシュしないと言ったように、ブラウザはそれを行います。だからこれはあなたが求めているものかもしれませんし、そうではないかもしれません...しかしあなたはjavascriptを使って画像をプリロードすることができます。プリロードするすべての画像を配列に配置し、その配列内のすべての画像を非表示のimg要素に配置することで、画像を効果的にプリロード(またはキャッシュ)します。

var images = [
'/path/to/image1.png',
'/path/to/image2.png'
];

$(images).each(function() {
var image = $('<img />').attr('src', this);
});

2
画像を(表示せずに)1ページにプリロードしてから、次のページに表示することは可能でしょうか?
Logan Besecker 2012

2
私の知る限り、あるページに画像をプリロードすると、その画像はブラウザのキャッシュに入力され、他のページにすばやく表示されます。これが間違っている場合は、誰かが私を訂正してください。
Trav McKinney 2012

3

あなたが見ることができるいくつかのことがあります:

画像
のプリロード.htaccessファイルでのキャッシュ時間の設定画像の
ファイルサイズとそれらをエンコードするbase64。

プリロード:http//perishablepress.com/3-ways-preload-images-css-javascript-ajax/

キャッシング:http//www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html

base64エンコーディングにはいくつかの異なる考えがあり、httpリクエストが帯域幅を圧迫すると言う人もいれば、「知覚される」読み込みの方が優れていると言う人もいます。これは空中に置いておきます。


3

質問に「JavaScriptを使用する」と書かれていてもprefetch、リンクタグの属性を使用して任意のアセットをプリロードできます。この記事の執筆時点(2016年8月10日)では、Safariではサポートされていませんが、他のほとんどの場所でサポートされています。

<link rel="prefetch" href="(url)">

サポートの詳細については、こちらをご覧ください:http//caniuse.com/#search=prefetch

IE 9,10はcaniuse、Microsoftがサポートを終了したため、マトリックスにリストされていないことに注意してください。

したがって、JavaScriptの使用に本当に固執している場合は、jqueryを使用して、これらの要素をページに動的に追加することもできます;-)


1
ナイスナイスナイスナイス!
Bhargav Nanekalva 2017

2

回答を完全にするための追加:HTMLによるプリロード

<link rel="preload" href="bg-image-wide.png" as="image">

他のプリロード機能も存在しますが、次のような目的に完全に適合するものはありません<link rel="preload">

  • <link rel="prefetch">は長い間ブラウザでサポートされてきましたが、次のナビゲーション/ページの読み込み(次のページに移動するときなど)で使用されるリソースをプリフェッチすることを目的としています。これは問題ありませんが、現在のページでは役に立ちません。さらに、ブラウザはプリフェッチリソースにプリロードリソースよりも低い優先度を与えます—現在のページは次のページよりも重要です。詳細については、リンクの先読みに関するFAQを参照してください。
  • <link rel="prerender">指定されたWebページをバックグラウンドでレンダリングし、ユーザーがそのWebページに移動した場合の読み込みを高速化します。ユーザーの帯域幅を浪費する可能性があるため、Chromeはプリレンダーを代わりにNoStateプリフェッチとして扱います。
  • <link rel="subresource"> しばらく前にChromeでサポートされ、プリロードと同じ問題に取り組むことを目的としていましたが、問題がありました。アイテムの優先順位を決定する方法がなかったため(当時は存在しなかったため)、すべてかなり低い優先度でフェッチされました。

スクリプトベースのリソースローダーは数多くありますが、ブラウザーのフェッチ優先順位付けキューに対する機能はなく、ほぼ同じパフォーマンスの問題が発生します。

ソース:https//developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content


これは受け入れられた答えでなければなりません。ありがとう!
Renan Coelho

1

JSを介した非同期プリロード画像についても同様の答えがあります。それらを動的にロードすることは、それらを通常ロードすることと同じです。それらはキャッシュされます。

キャッシュに関しては、ブラウザを制御することはできませんが、サーバーを介して設定することはできます。本当に新しいリソースをオンデマンドでロードする必要がある場合は、キャッシュバスター手法を使用して新しいリソースを強制的にロードできます。


1

画像をレイジーロードするのと同様の手法を使用しますが、最初のロード時にJavascriptがブラウザのキャッシュにアクセスしないことに気付かずにはいられません。

私の例:

ホームページに回転するバナーがあり、JavaScriptが次の画像を読み込んだり2秒待ったりするよりも、スライダーが2秒待つ4つの画像があります。

これらの画像には、変更するたびに変更される一意のURLがあるため、ブラウザに1年間キャッシュされるキャッシュヘッダーを取得します。

max-age: 31536000, public

Chrome Devtoolsを開いて、[キャッシュを無効にする]オプションがアクティブになっていないことを確認し、(キャッシュをクリアした後)初めてページを読み込むと、すべての画像がフェッチされ、ステータスが200になります。バナー内のすべての画像の完全なサイクルの後、ネットワークリクエストは停止し、キャッシュされた画像が使用されます。

これで、定期的に更新するか、サブページに移動してクリックすると、キャッシュにある画像が無視されているように見えます。Chromedevtoolsの[ネットワーク]タブに「ディスクキャッシュから」という灰色のメッセージが表示されると思います。代わりに、リクエストが2秒ごとに通過し、灰色ではなく緑色のステータスサークルが表示され、データが転送されているのがわかります。そのため、JavaScriptからキャッシュにまったくアクセスされていないように見えます。ページが読み込まれるたびに画像を取得するだけです。

したがって、ホームページへの各リクエストは、画像のキャッシュポリシーに関係なく、4つのリクエストをトリガーします。

上記と、ほとんどのWebサーバーとブラウザーが現在サポートしている新しいhttp2標準を考慮すると、http2はすべての画像をほぼ同時にロードするため、遅延読み込みの使用を停止することをお勧めします。

これがChromeDevtoolsのバグである場合、まだ誰も気づいていないことに本当に驚いています。;)

これが当てはまる場合、遅延読み込みを使用すると、帯域幅の使用量が増えるだけです。

私が間違っている場合は私を訂正してください。:)



0

私は常に、Konva JS:ImageEvents説明されている例を使用して画像を読み込むことを好みます。

  1. 次のように、オブジェクトまたは配列として画像URLのリストを用意する必要があります。

    var sources = { lion: '/assets/lion.png', monkey: '/assets/monkey.png' };

  2. 関数定義を定義します。関数定義では、画像URLのリストと、引数リスト内のコールバック関数を受け取ります。これにより、画像の読み込みが完了したら、Webページで実行を開始できます。

    function loadImages(sources, callback) {
                var images = {};
                var loadedImages = 0;
                var numImages = 0;
                for (var src in sources) {
                    numImages++;
                }
                for (var src in sources) {
                    images[src] = new Image();
                    images[src].onload = function () {
                        if (++loadedImages >= numImages) {
                            callback(images);
                        }
                    };
                    images[src].src = sources[src];
                }
            }

  1. 最後に、関数を呼び出す必要があります。たとえば、jQueryDocumentReadyから呼び出すことができます。

$(document).ready(function (){ loadImages(sources, buildStage); });


0

今日、あなたの画像レンダリングプロセスをキャッシュして改善するためにグーグルによって提案された新しいテクニックがあります:

  1. JavaScript Lazysizesファイルを含めます:lazysizes.js
  2. 使用するhtmlファイルにファイルを追加します。 <script src="lazysizes.min.js" async></script>
  3. lazyloadクラスを画像に追加します。 <img data-src="images/flower3.png" class="lazyload" alt="">
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.