web-dev-qa-db-fra.com

La meilleure façon définitive de précharger des images en utilisant JavaScript / jQuery?

Je suis pleinement conscient que cette question a été posée et répondue partout, à la fois sur SO et off. Cependant, à chaque fois, il semble y avoir une réponse différente, par exemple this =, ceci et que .

Je ne me soucie pas de savoir s'il utilise jQuery ou non - ce qui est important, c'est que cela fonctionne et qu'il existe plusieurs navigateurs.]

Alors, quelle est la meilleure façon de précharger les images?

50
Skilldrick

Malheureusement, cela dépend de votre objectif. Si vous prévoyez d'utiliser les images à des fins de style, votre meilleur pari est d'utiliser des sprites. http://www.alistapart.com/articles/sprites2

Cependant, si vous prévoyez d'utiliser les images dans les balises <img>, vous voudrez les précharger avec

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

(source modifiée tirée de Quelle est la meilleure façon de précharger plusieurs images en JavaScript? )

l'utilisation de new Image() n'entraîne pas de frais d'utilisation des méthodes DOM mais une nouvelle demande pour l'image spécifiée sera ajoutée à la file d'attente. Comme l'image n'est, à ce stade, pas réellement ajoutée à la page, aucun nouveau rendu n'est impliqué. Je recommanderais cependant d'ajouter cela à la fin de votre page (comme tous vos scripts devraient l'être, si possible) pour l'empêcher de contenir des éléments plus critiques.

Modifier: modifié pour refléter correctement le commentaire, soulignant que des objets Image distincts sont nécessaires pour fonctionner correctement. Merci, et mon mal de ne pas l'avoir vérifié de plus près.

Edit2: édité pour rendre la réutilisabilité plus évidente

Modifier 3 (3 ans plus tard):

En raison des changements dans la façon dont les navigateurs gèrent les images non visibles (affichage: aucun ou, comme dans cette réponse, jamais annexé au document), une nouvelle approche du préchargement est préférée.

Vous pouvez utiliser une demande Ajax pour forcer la récupération précoce des images. En utilisant jQuery, par exemple:

jQuery.get(source);

Ou dans le contexte de notre exemple précédent, vous pourriez faire:

function preload(sources)
{
  jQuery.each(sources, function(i,source) { jQuery.get(source); });
}

Notez que cela ne s'applique pas au cas des sprites qui sont bien tels quels. C'est juste pour des choses comme des galeries de photos ou des curseurs/carrousels avec des images où les images ne se chargent pas car elles ne sont pas visibles initialement.

Notez également que cette méthode ne fonctionne pas pour IE (ajax n'est normalement pas utilisé pour récupérer les données d'image).

65

Spriting

Comme d'autres l'ont mentionné, le sprite fonctionne très bien pour diverses raisons, cependant, il n'est pas aussi bon que prévu.

  • À la hausse, vous finissez par faire une seule demande HTTP pour vos images. YMMV cependant.
  • En bas, vous chargez tout dans une seule requête HTTP. Étant donné que la plupart des navigateurs actuels sont limités à 2 connexions simultanées, la demande d'image peut bloquer d'autres demandes. Par conséquent, YMMV et quelque chose comme l'arrière-plan de votre menu peuvent ne pas s'afficher un peu.
  • Plusieurs images partagent la même palette de couleurs, il y a donc des économies, mais ce n'est pas toujours le cas et même si c'est négligeable.
  • La compression est améliorée car il y a plus de données partagées entre les images.

Traiter des formes irrégulières est cependant délicat. La combinaison de toutes les nouvelles images dans la nouvelle est une autre gêne.

approche jack faible utilisant des balises <img>

Si vous cherchez la solution la plus définitive alors vous devriez opter pour l'approche low-jack que je préfère encore. Créez des liens <img> vers les images à la fin de votre document et définissez width et height sur 1x1 pixel et placez-les en plus dans une div cachée. S'ils se trouvent à la fin de la page, ils seront chargés après d'autres contenus.

14
aleemb

En janvier 2013, aucune des méthodes décrites ici ne fonctionnait pour moi, alors voici ce qui a fonctionné, testé et fonctionnant avec Chrome 25 et Firefox 18. Utilise jQuery et ce plugin = pour contourner les caprices des événements de chargement:

function preload(sources, callback) {
    if(sources.length) {
        var preloaderDiv = $('<div style="display: none;"></div>').prependTo(document.body);

        $.each(sources, function(i,source) {
            $("<img/>").attr("src", source).appendTo(preloaderDiv);

            if(i == (sources.length-1)) {
                $(preloaderDiv).imagesLoaded(function() {
                    $(this).remove();
                    if(callback) callback();
                });
            }
        });
    } else {
        if(callback) callback();
    }
}

Usage:

preload(['/img/a.png', '/img/b.png', '/img/c.png'], function() { 
    console.log("done"); 
});

Notez que vous obtiendrez des résultats mitigés si le cache est désactivé, ce qui est le cas par défaut sur Chrome lorsque les outils de développement sont ouverts, alors gardez cela à l'esprit.

6
Mahn

À mon avis, l'utilisation de Multipart XMLHttpRequest introduite par certaines bibliothèques sera une solution préférée dans les années suivantes. Cependant IE <v8, ne prend toujours pas en charge les données: uri (même IE8 a une prise en charge limitée, autorisant jusqu'à 32 Ko). Voici une implémentation du préchargement d'image parallèle - http: //code.google.com/p/core-framework/wiki/ImagePreloading , il est intégré dans le cadre mais vaut quand même le coup d'œil.

3
Angel

C'était il y a longtemps donc je ne sais pas combien de personnes sont toujours intéressées par le préchargement d'une image.

Ma solution était encore plus simple.

Je viens d'utiliser CSS.

#hidden_preload {
    height: 1px;
    left: -20000px;
    position: absolute;
    top: -20000px;
    width: 1px;
}
1
Scott Cleland

Pour mon cas d'utilisation, j'avais un carrousel avec des images plein écran que je voulais précharger. Cependant, étant donné que les images s'affichent dans l'ordre et que leur chargement peut prendre quelques secondes, il est important que je les charge dans l'ordre, séquentiellement.

Pour cela, j'ai utilisé la méthode waterfall() de la bibliothèque async ( https://github.com/caolan/async#waterfall )

        // Preload all images in the carousel in order.
        image_preload_array = [];
        $('div.carousel-image').each(function(){
            var url = $(this).data('image-url');
            image_preload_array.Push(function(callback) {
                var $img = $('<img/>')
                $img.load(function() {
                    callback(null);
                })[0].src = url;
            });
        });
        async.waterfall(image_preload_array);

Cela fonctionne en créant un tableau de fonctions, chaque fonction reçoit le paramètre callback() dont elle a besoin pour exécuter la fonction suivante dans le tableau. Le premier paramètre de callback() est un message d'erreur, qui quittera la séquence si une valeur non nulle est fournie, nous passons donc null à chaque fois.

0
DanH

Voici ma solution simple avec un fondu sur l'image après son chargement.

    function preloadImage(_imgUrl, _container){
        var image = new Image();
            image.src = _imgUrl;
            image.onload = function(){
                $(_container).fadeTo(500, 1);
            };
        }
0
Afonso Praça