JavaScriptを使用した画像のプリロード


263

以下に記述した機能は、現在一般的に使用されているほとんどすべてのブラウザーで画像をプリロードするのに十分ですか?

function preloadImage(url)
{
    var img=new Image();
    img.src=url;
}

ループして、preloadImage各URLの関数を呼び出す画像URLの配列があります。


19
一部の(すべての?)ブラウザーは、使用していない場合、数秒後にイメージを解放することに注意してください。これを回避するには、imgオブジェクトへの参照を、たとえば親スコープの配列に保持します。
タムリン2014年

3
「画像を公開」とはどういう意味ですか?それがブラウザによってキャッシュされた場合、それはそこに留まりますよね?
Francisc

56
少し短い:(new Image()).src = url;
mrzmyr 2014年

20
これは、Chrome devtoolが開いていて、ネットワークパネルで「chacheを無効にする」が有効になっている場合は機能しないことに注意してください
Wayou

6
さらに短く:new Image().src = url;
Daniel X Moore

回答:


163

はい。これはすべての主要なブラウザで動作するはずです。


48
司会者注:これを「回答ではない」としてフラグを立てないでください。実際、これは、尋ねられた質問に対する直接の回答です。答えが間違っている、または証拠によるサポートが不十分であると思われる場合は、反対票を投じてください。
コーディグレイ

43

これを試してみてください。

var images = [];
function preload() {
    for (var i = 0; i < arguments.length; i++) {
        images[i] = new Image();
        images[i].src = preload.arguments[i];
    }
}

//-- usage --//
preload(
    "http://domain.tld/gallery/image-001.jpg",
    "http://domain.tld/gallery/image-002.jpg",
    "http://domain.tld/gallery/image-003.jpg"
)

ソース:http : //perishablepress.com/3-ways-preload-images-css-javascript-ajax/


3
onload画像のハンドラはありません
Benny

12
なぜこれが良いのか説明してもらえますか?
JJJ 2016年

2
@BeNice私はあなたが誤解していると思います、画像の読み込みは非同期であるため、onload状態を処理する必要があるか、メモリ内の画像をインスタンス化しているだけです。
ベニー

3
このソリューションを使用する場合は、i変数のvarステートメントを忘れないでください。それ以外の場合はあなたがvarステートメントを忘れてしまったことを知っている限り解決することは本当に難しいですエラーを(引き起こす可能性がグローバルに設定されます。for (var i = 0.....
Mohammer

2
@Mohammerに感謝します。提供したリンクからコードをコピーしました。今すぐコードを編集して追加しますvar
clintgh

26

私の場合、onloadイベントのコールバックを関数に追加すると便利でした。

function preloadImage(url, callback)
{
    var img=new Image();
    img.src=url;
    img.onload = callback;
}

そして、すべてのコールバックでプリロードされる画像へのURLの配列の場合のためにそれをラップします:https : //jsfiddle.net/4r0Luoy7/

function preloadImages(urls, allImagesLoadedCallback){
    var loadedCounter = 0;
  var toBeLoadedNumber = urls.length;
  urls.forEach(function(url){
    preloadImage(url, function(){
        loadedCounter++;
            console.log('Number of loaded images: ' + loadedCounter);
      if(loadedCounter == toBeLoadedNumber){
        allImagesLoadedCallback();
      }
    });
  });
  function preloadImage(url, anImageLoadedCallback){
      var img = new Image();
      img.onload = anImageLoadedCallback;
      img.src = url;
  }
}

// Let's call it:
preloadImages([
    '//upload.wikimedia.org/wikipedia/commons/d/da/Internet2.jpg',
  '//www.csee.umbc.edu/wp-content/uploads/2011/08/www.jpg'
], function(){
    console.log('All images were loaded');
});

19

CSS2の代替:http : //www.thecssninja.com/css/even-better-image-preloading-with-css2

body:after {
  content: url(img01.jpg) url(img02.jpg) url(img03.jpg);
  display: none; 
}

CSS3代替:https : //perishablepress.com/preload-images-css3/ (H / T Linh Dam)

.preload-images {
  display: none; 
  width: 0;
  height: 0;
  background: url(img01.jpg),
              url(img02.jpg),
              url(img03.jpg);
}

注:コンテナ内の画像display:noneはプリロードされない場合があります。おそらく、visibility:hiddenの方がうまく機能しますが、これはテストしていません。これを指摘してくれたMarco Del Valleに感謝します


mplungjanに感謝します。この特定のケースでは役に立ちませんが、知っておくと役に立ちます。
Francisc

5
ページが読み込みイベントを開始する前にこれらの画像をダウンロードする必要があるため、ページの読み込みが遅くなると私は正しく言っていますか?
ジャクビゾン2015年

3
これらがすべてのブラウザで機能するとは思いません。Chromeでは画像が表示されるまで読み込まれないことを知っています。表示を削除する必要があります:なし。代わりに、見えないように配置します。必要に応じてすべてが読み込まれた後、JSで非表示にできます。
Bullyen

3
要素の背景画像display: noneはプリロードされません。
マルキッツォ

1
この方法は私だけのために機能しました(1)を使用しなかったdisplay: none、(2)を使用しなかったwidth/height: 0、(3)配置no-repeat、および画像が外側になるような位置(画像が-<width>px -<height>pxそこに到達するため、画像がすべて100pxの場合あまりの高さや、使用することができます0 -100pxつまり、url(...) no-repeat 0 -100px
アレクシスウィルケ

11

可能性のある問題を防ぐために、try / catchを使用することをお勧めします。

OOP:

    var preloadImage = function (url) {
        try {
            var _img = new Image();
            _img.src = url;
        } catch (e) { }
    }

標準:

    function preloadImage (url) {
        try {
            var _img = new Image();
            _img.src = url;
        } catch (e) { }
    }

また、私はDOMを愛していますが、古い愚かなブラウザーはDOMの使用に問題がある可能性があるため、freedevの貢献に反して、完全にIMHOを回避してください。Image()は古いごみブラウザでのサポートが向上しています。


7
私はこれがJavaScriptで画像をロードするときにエラーをキャッチする方法だとは思いません-使用できる(すべき?)_ img.onerrorのようなものがあります
Greg0ry

3
「考えられる問題」とは何ですか?
Kissaki

コマンドのサポートなどの問題。サポートが必要なブラウザーがjavascriptコマンドをサポートしているかどうかを確認するには、「使用できる」サイトを確認してください。
デイブ、

10

このアプローチはもう少し複雑です。ここでは、プリロードされたすべてのイメージをコンテナーに格納します。divの場合もあります。そして、画像を表示したり、DOM内で適切な位置に移動したりできます。

function preloadImg(containerId, imgUrl, imageId) {
    var i = document.createElement('img'); // or new Image()
    i.id = imageId;
    i.onload = function() {
         var container = document.getElementById(containerId);
         container.appendChild(this);
    };
    i.src = imgUrl;
}

ここ試してください。コメントもいくつか追加しました


7
const preloadImage = src => 
  new Promise(r => {
    const image = new Image()
    image.onload = r
    image.onerror = r
    image.src = src
  })


// Preload an image
await preloadImage('https://picsum.photos/100/100')

// Preload a bunch of images in parallel 
await Promise.all(images.map(x => preloadImage(x.src)))

5

この意志の仕事をはい、しかし、ブラウザがします制限します(4-8間)の実際の呼び出し、したがってないキャッシュ/ PRELOAD全ての所望の画像を。

これを行うより良い方法は、次のようにイメージを使用する前にonloadを呼び出すことです。

function (imageUrls, index) {  
    var img = new Image();

    img.onload = function () {
        console.log('isCached: ' + isCached(imageUrls[index]));
        *DoSomething..*

    img.src = imageUrls[index]
}

function isCached(imgUrl) {
    var img = new Image();
    img.src = imgUrl;
    return img.complete || (img .width + img .height) > 0;
}

このブラウザ制限についての参照をリンクしていただけませんか?
nulll

リファレンスを見つけるのは難しいですが(少なくとも1つは見つかりませんでした)、Chrome開発者ツール(f12)でChromeのネットワークタブを使用してキャッシュとサーバーの呼び出しから読み込まれたものを詳しく調べながら、自分のプロジェクトを使用してこれをテストしました。Firefoxでもモバイルでも同じ動作が見られました。
Robin

1
-1ここの最初の文の主張を注意深くテストしたところ、少なくとも最近のブラウザでは、それが誤りであることがわかりました。stackoverflow.com/a/56012084/1709587を参照してください。はい、ブラウザが送信する並列HTTPリクエストの最大数には制限がありますが、質問に示されている方法で実行しても、最終的にはpreloadImageを呼び出すすべてのURLをリクエストするようになります。
マークアメリー

5

これが私のアプローチです:

var preloadImages = function (srcs, imgs, callback) {
    var img;
    var remaining = srcs.length;
    for (var i = 0; i < srcs.length; i++) {
        img = new Image;
        img.onload = function () {
            --remaining;
            if (remaining <= 0) {
                callback();
            }
        };
        img.src = srcs[i];
        imgs.push(img);
    }
};

4

ECMAScript 2017準拠ブラウザーのソリューション

注:これは、Babelのようなトランスパイラーを使用している場合にも機能します。

'use strict';

function imageLoaded(src, alt = '') {
    return new Promise(function(resolve) {
        const image = document.createElement('img');

        image.setAttribute('alt', alt);
        image.setAttribute('src', src);

        image.addEventListener('load', function() {
            resolve(image);
        });
    });
}

async function runExample() {
    console.log("Fetching my cat's image...");

    const myCat = await imageLoaded('https://placekitten.com/500');

    console.log("My cat's image is ready! Now is the time to load my dog's image...");

    const myDog = await imageLoaded('https://placedog.net/500');

    console.log('Whoa! This is now the time to enable my galery.');

    document.body.appendChild(myCat);
    document.body.appendChild(myDog);
}

runExample();

すべての画像が読み込まれるのを待つこともできます。

async function runExample() {
    const [myCat, myDog] = [
        await imageLoaded('https://placekitten.com/500'),
        await imageLoaded('https://placedog.net/500')
    ];

    document.body.appendChild(myCat);
    document.body.appendChild(myDog);
}

または、Promise.allそれらを並行してロードするために使用します。

async function runExample() {
    const [myCat, myDog] = await Promise.all([
        imageLoaded('https://placekitten.com/500'),
        imageLoaded('https://placedog.net/500')
    ]);

    document.body.appendChild(myCat);
    document.body.appendChild(myDog);
}

Promisesの詳細

「非同期」関数の詳細

解体任務についての詳細

ECMAScript 2015の詳細

ECMAScript 2017の詳細


2

問題のアプローチは、画像がダウンロードされてキャッシュされるのをトリガーするのに十分であることを確認できます(ブラウザが応答ヘッダーを介してそうすることを禁止している場合を除きます)。

  • Chrome 74
  • Safari 12
  • Firefox 66
  • エッジ17

これをテストするために、子猫の写真を提供する前にそれぞれが10秒間スリープするいくつかのエンドポイントを持つ小さなWebアプリケーションを作成しました。その後、私は2つの含まれているそのうちの一つのウェブページ、添加<script>子猫のそれぞれが使用してプリロードされたタグpreloadImage質問から機能、および他のその使用ページ上のすべての子猫含む<img>タグ。

上記のすべてのブラウザーで、最初にプリローダーページにアクセスし、しばらく待ってから<img>タグのあるページに移動すると、子猫がすぐにレンダリングされることがわかりました。これは、プリローダーがテストしたすべてのブラウザーのキャッシュに子猫を正常にロードしたことを示しています。

これをテストするために使用したアプリケーションは、https://github.com/ExplodingCabbage/preloadImage-testで確認または試すことができます

特に、ループされる画像の数が、Robinの回答が示唆するのとは逆に、ブラウザが一度に行う並列リクエストの数を超える場合でも、この手法は上記のブラウザで機能することに注意してください。もちろん、画像のプリロードの速度は、ブラウザが送信する並列リクエストの数によって制限されますが、最終的に、呼び出す画像の各URLを要求preloadImage()します。


画像がメモリまたはディスクのどちらにキャッシュされるかは重要ですか?メモリにキャッシュされる@clintghメソッドとは対照的に、OPメソッドはディスクにキャッシュされるようです。
クリスL

1

このコードをindex.htmlに移動して、任意のURLから画像をプリロードできます。

<link rel="preload" href="https://via.placeholder.com/160" as="image">

0

ブラウザは、head内のリンクタグを使用すると最適に動作します。

export function preloadImages (imageSources: string[]): void {
  imageSources
    .forEach(i => {
      const linkEl = document.createElement('link');
      linkEl.setAttribute('rel', 'preload');
      linkEl.setAttribute('href', i);
      linkEl.setAttribute('as', 'image');
      document.head.appendChild(linkEl);
    });
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.