image-preloader preload - Il modo migliore per precaricare le immagini usando JavaScript / jQuery?





images onload (8)


Per il mio caso d'uso ho avuto un carosello con immagini a schermo intero che volevo precaricare. Tuttavia, poiché le immagini vengono visualizzate in ordine, e potrebbero essere necessari alcuni secondi per caricarle, è importante caricarle in ordine, in sequenza.

Per questo ho usato il metodo waterfall() della libreria 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);

Questo funziona creando una serie di funzioni, ogni funzione riceve il parametro callback() che deve essere eseguito per chiamare la funzione successiva nell'array. Il primo parametro di callback() è un messaggio di errore, che uscirà dalla sequenza se viene fornito un valore non nullo, quindi passiamo null ogni volta.

Sono pienamente consapevole che questa domanda è stata posta e ha risposto ovunque, sia su SO che fuori. Tuttavia, ogni volta sembra che ci sia una risposta diversa, per esempio this , this e that .

Non mi interessa se usi jQuery o no - l'importante è che funzioni, ed è cross-browser.]

Quindi, qual è il modo migliore per precaricare le immagini?




sprite

Come altri hanno già accennato, lo sprite funziona abbastanza bene per una serie di motivi, tuttavia, non è buono come è stato dimostrato.

  • Sul lato positivo, si finisce per fare solo una richiesta HTTP per le tue immagini. YMMV però.
  • Sul lato negativo si sta caricando tutto in una richiesta HTTP. Poiché la maggior parte dei browser correnti è limitata a 2 connessioni simultanee, la richiesta di immagine può bloccare altre richieste. Quindi YMMV e qualcosa come lo sfondo del tuo menu potrebbe non essere visualizzato per un po '.
  • Più immagini condividono la stessa tavolozza di colori, quindi c'è un po 'di risparmio, ma questo non è sempre il caso e anche così è trascurabile.
  • La compressione è migliorata perché vi sono più dati condivisi tra le immagini.

Trattare con forme irregolari è però complicato. Unire tutte le nuove immagini a quelle nuove è un altro fastidio.

Approccio low-jack usando i tag <img>

Se stai cercando la soluzione più definitiva , dovresti seguire l'approccio low-jack che preferisco ancora. Crea collegamenti <img> alle immagini alla fine del documento e imposta width e height a 1x1 pixel e aggiungili in un div nascosto. Se sono alla fine della pagina, saranno caricati dopo altri contenuti.




Sfortunatamente, ciò dipende dal tuo scopo. Se si prevede di utilizzare le immagini per scopi di stile, la soluzione migliore è utilizzare gli sprite. http://www.alistapart.com/articles/sprites2

Tuttavia, se prevedi di utilizzare le immagini nei tag <img>, dovrai prima caricarle con

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

(fonte modificata presa da Qual è il modo migliore per precaricare più immagini in JavaScript? )

l'utilizzo della new Image() non comporta la spesa per l'utilizzo dei metodi DOM ma una nuova richiesta per l'immagine specificata verrà aggiunta alla coda. Poiché l'immagine è, a questo punto, non effettivamente aggiunta alla pagina, non è previsto alcun re-rendering. Ti consiglio, tuttavia, di aggiungere questo alla fine della pagina (come dovrebbero essere tutti gli script, quando possibile) per evitare che registri elementi più critici.

Modifica: modificato per riflettere correttamente il commento sottolineando che gli oggetti Image separati sono necessari per funzionare correttamente. Grazie, e il mio male per non averlo controllato più da vicino.

Edit2: modificato per rendere la riusabilità più ovvia

Modifica 3 (3 anni dopo):

A causa di cambiamenti nel modo in cui i browser gestiscono le immagini non visibili (display: none o, come in questa risposta, non è mai stato aggiunto al documento) è preferibile un nuovo approccio al pre-caricamento.

È possibile utilizzare una richiesta Ajax per forzare il recupero anticipato delle immagini. Usando jQuery, ad esempio:

jQuery.get(source);

O nel contesto del nostro precedente esempio, potresti fare:

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

Nota che questo non si applica al caso degli sprites che vanno bene così com'è. Questo è solo per cose come gallerie fotografiche o cursori / caroselli con immagini in cui le immagini non vengono caricate perché inizialmente non sono visibili.

Si noti inoltre che questo metodo non funziona per IE (ajax normalmente non viene utilizzato per recuperare i dati dell'immagine).




A mio parere, l'utilizzo di Multipart XMLHttpRequest introdotto da alcune librerie sarà una soluzione preferita negli anni successivi. Tuttavia IE <v8, ancora non supporta i dati: uri (anche IE8 ha un supporto limitato, consentendo fino a 32kb). Ecco un'implementazione del preloading dell'immagine parallela: http://code.google.com/p/core-framework/wiki/ImagePreloading , è impacchettato in un framework ma vale comunque la pena dare un'occhiata.







Questo è stato da molto tempo fa quindi non so quante persone sono ancora interessati a precaricare un'immagine.

La mia soluzione era ancora più semplice.

Ho appena usato i CSS.

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



A partire da gennaio 2013 nessuno dei metodi descritti qui ha funzionato per me, quindi ecco cosa ha invece, testato e funzionante con Chrome 25 e Firefox 18. Utilizza jQuery e questo plug-in per aggirare le anomalie dell'evento di caricamento:

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();
    }
}

Uso:

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

Tieni presente che otterrete risultati misti se la cache è disabilitata, che è di default su Chrome quando gli strumenti di sviluppo sono aperti, quindi tienilo a mente.




JP, Dopo aver verificato la tua soluzione, stavo ancora avendo problemi in Firefox, dove non avrebbe precaricato le immagini prima di spostarsi con il caricamento della pagina. Ho scoperto questo mettendo un po 'di sleep(5) nel mio script lato server. Ho implementato la seguente soluzione basata sulla tua che sembra risolvere questo problema.

Fondamentalmente ho aggiunto un callback al tuo plugin jQuery per il preload, in modo che venga chiamato dopo che tutte le immagini sono state caricate correttamente.

// Helper function, used below.
// Usage: ['img1.jpg','img2.jpg'].remove('img1.jpg');
Array.prototype.remove = function(element) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] == element) { this.splice(i,1); }
  }
};

// Usage: $(['img1.jpg','img2.jpg']).preloadImages(function(){ ... });
// Callback function gets called after all images are preloaded
$.fn.preloadImages = function(callback) {
  checklist = this.toArray();
  this.each(function() {
    $('<img>').attr({ src: this }).load(function() {
      checklist.remove($(this).attr('src'));
      if (checklist.length == 0) { callback(); }
    });
  });
};

Fuori di interesse, nel mio contesto, sto usando questo come segue:

$.post('/submit_stuff', { id: 123 }, function(response) {
  $([response.imgsrc1, response.imgsrc2]).preloadImages(function(){
    // Update page with response data
  });
});

Speriamo che questo aiuti qualcuno che viene in questa pagina da Google (come ho fatto io) a cercare una soluzione per il precaricamento delle immagini sulle chiamate Ajax.





javascript jquery image-preloader