Wie können Sie ein Bild in Javascript zwischenspeichern?

84

Meine Freunde und ich arbeiten an einer Website, auf der wir bestimmte Bilder zwischenspeichern möchten, um sie in Zukunft schneller anzuzeigen. Ich habe zwei Hauptfragen:

  1. Wie zwischenspeichert man ein Bild?
  2. Wie verwendet man ein Bild, wenn es zwischengespeichert wurde? (und nur um zu überprüfen, ob ein Bild auf Seite A zwischengespeichert ist, ist es möglich, es aus dem Cache aufzurufen, um es auf Seite B zu verwenden, oder?)

Kann auch festgelegt werden, wann die zwischengespeicherte Version des Bildes abläuft?

Es wäre sehr dankbar, wenn ein Beispiel und / oder ein Link zu einer Seite, die dies weiter beschreibt, enthalten wäre.

Wir können entweder rohes Javascript oder die jQuery-Version verwenden.

Logan Besecker
quelle
12
Das tust du nicht. Der Browser tut es.
Pointy
speichert der Browser Bilder automatisch zwischen?
Logan Besecker
8
@Logan: Ja, der Browser speichert Bilder automatisch zwischen, sofern Ihr Server die erforderlichen Header sendet, um dem Browser mitzuteilen, dass das Zwischenspeichern sicher ist. (Diese Header können dem Browser auch die
Ablaufzeit
Wie kann ich überprüfen, ob mein Browser die erforderlichen Header sendet?
Logan Besecker
1
@LoganBesecker Sie können die Antwortheader im Abschnitt "Netzwerk" der Entwicklungstools Ihres Browsers überprüfen.
Jlaceda

Antworten:

132

Sobald ein Bild in irgendeiner Weise in den Browser geladen wurde, befindet es sich im Browser-Cache und wird bei der nächsten Verwendung viel schneller geladen, unabhängig davon, ob diese Verwendung auf der aktuellen Seite oder auf einer anderen Seite erfolgt, solange sich das Bild befindet Wird verwendet, bevor es aus dem Browser-Cache abläuft.

Um Bilder vorzuspeichern, müssen Sie sie nur in den Browser laden. Wenn Sie eine Reihe von Bildern vorspeichern möchten, ist es wahrscheinlich am besten, dies mit Javascript zu tun, da es das Laden der Seite im Allgemeinen nicht aufhält, wenn es mit Javascript erstellt wird. Sie können das so machen:

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"]);

Diese Funktion kann beliebig oft aufgerufen werden und fügt jedes Mal mehr Bilder zum Precache hinzu.

Sobald Bilder wie folgt über Javascript vorinstalliert wurden, werden sie vom Browser im Cache gespeichert. Sie können einfach auf die normalen URLs an anderen Stellen (auf Ihren Webseiten) verweisen, und der Browser ruft diese URL aus dem Cache ab und nicht über den Netzwerk.

Im Laufe der Zeit füllt sich der Browser-Cache möglicherweise und wirft die ältesten Dinge weg, die seit einiger Zeit nicht mehr verwendet wurden. Irgendwann werden die Bilder aus dem Cache gelöscht, aber sie sollten eine Weile dort bleiben (abhängig davon, wie groß der Cache ist und wie viel anderes Durchsuchen durchgeführt wird). Jedes Mal, wenn die Bilder erneut vorgeladen oder auf einer Webseite verwendet werden, wird ihre Position im Browser-Cache automatisch aktualisiert, sodass sie weniger wahrscheinlich aus dem Cache gelöscht werden.

Der Browser-Cache ist seitenübergreifend und funktioniert daher für alle in den Browser geladenen Seiten. Sie können also an einer Stelle Ihrer Site vorcachen, und der Browser-Cache funktioniert dann für alle anderen Seiten Ihrer Site.


Beim Vorab-Caching wie oben werden die Bilder asynchron geladen, damit das Laden oder Anzeigen Ihrer Seite nicht blockiert wird. Wenn Ihre Seite jedoch viele eigene Bilder enthält, können diese Precache-Bilder um Bandbreite oder Verbindungen mit den auf Ihrer Seite angezeigten Bildern konkurrieren. Normalerweise ist dies kein auffälliges Problem, aber bei einer langsamen Verbindung kann dieses Vorspeichern das Laden der Hauptseite verlangsamen. Wenn es in Ordnung war, dass Bilder vor dem Laden zuletzt geladen wurden, können Sie eine Version der Funktion verwenden, die mit dem Vorladen wartet, bis alle anderen Seitenressourcen bereits geladen wurden.

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);
jfriend00
quelle
In diesem Beispiel erstellen Sie für jede URL ein neues Bildobjekt. Wenn Sie die Variable img außerhalb der Schleife festlegen und nur die src aktualisieren, sollte dies den gleichen Effekt haben und die Ressourcen
reduzieren
2
@cadlac - Um sicherzugehen, dass der Browser tatsächlich jedes Bild herunterlädt und zwischenspeichert, müssen Sie warten, bis ein Bild vollständig heruntergeladen wurde, bevor Sie eine neue .src-Eigenschaft festlegen. Andernfalls könnte der Browser den vorherigen Download einfach stoppen und ihn nie erfolgreich zwischenspeichern.
jfriend00
Es scheint auf neueren Versionen von Browsern zu funktionieren, ohne zu warten, aber Sie machen einen guten Punkt. Ich muss es in einigen älteren Browsern ausprobieren, um die Kompatibilität zu
überprüfen
@ Cadlac - keine Notwendigkeit. Ich habe den Code aktualisiert, um das Image()Element aus der Liste zu entfernen, wenn das Laden des Bildes abgeschlossen ist. Es ist sicherer zu warten, bis das Bild vollständig geladen ist.
jfriend00
1
Ich habe eine weitere Version des Skripts hinzugefügt, die wartet, bis andere Dokumentressourcen geladen wurden, damit das Vorladen von Bildern nicht mit dem Laden der sichtbaren Seitenressourcen um die Bandbreite konkurriert.
jfriend00
13

Wie @Pointy sagte, dass Sie Bilder nicht mit Javascript zwischenspeichern, macht der Browser das. Das ist vielleicht das, wonach Sie fragen und vielleicht auch nicht ... aber Sie können Bilder mit Javascript vorladen. Indem Sie alle Bilder, die Sie vorab laden möchten, in ein Array einfügen und alle Bilder in diesem Array in versteckte img-Elemente einfügen, laden Sie die Bilder effektiv vor (oder zwischenspeichern).

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

$(images).each(function() {
var image = $('<img />').attr('src', this);
});
Trav McKinney
quelle
2
Wäre es möglich, ein Bild auf einer Seite vorzuladen (ohne es anzuzeigen) und es dann auf der nächsten Seite anzuzeigen?
Logan Besecker
2
Wenn Sie ein Bild auf einer Seite vorladen, wird es meines Wissens in den Browser-Cache eingegeben und auf jeder anderen Seite schneller angezeigt. Wenn dies falsch ist, korrigiert mich bitte jemand.
Trav McKinney
4

Obwohl Ihre Frage "Verwenden von Javascript" lautet, können Sie das prefetchAttribut eines Link-Tags verwenden, um ein Asset vorab zu laden. Zum jetzigen Zeitpunkt (10. August 2016) wird es in Safari nicht unterstützt, ist aber so ziemlich überall sonst:

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

Weitere Informationen zum Support finden Sie hier: http://caniuse.com/#search=prefetch

Beachten Sie, dass IE 9,10 nicht in der caniuseMatrix aufgeführt sind, da Microsoft die Unterstützung für sie eingestellt hat.

Wenn Sie also wirklich mit Javascript beschäftigt sind, können Sie jquery verwenden, um diese Elemente auch dynamisch zu Ihrer Seite hinzuzufügen ;-)

Brad Parks
quelle
1
Schön schön schön schön!
Bhargav Nanekalva
3

Es gibt einige Dinge, die Sie sich ansehen können:

Vorladen Ihrer Bilder
Festlegen einer Cache-Zeit in einer .htaccess-Datei
Dateigröße der Bilder und Base64-Codierung.

Vorladen: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/

Caching: http://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html

Es gibt ein paar verschiedene Gedanken für die Base64-Codierung, einige sagen, dass die http-Anforderungen die Bandbreite blockieren, während andere sagen, dass das "wahrgenommene" Laden besser ist. Ich werde das in der Luft lassen.

Tango Bravo
quelle
3

Zur Vollständigkeit der Antworten hinzufügen: Vorladen mit HTML

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

Es gibt andere Vorladefunktionen, aber keine ist so zweckmäßig wie <link rel="preload">:

  • <link rel="prefetch">wird seit langem in Browsern unterstützt, ist jedoch zum Vorabrufen von Ressourcen gedacht, die beim nächsten Navigations- / Seitenladen verwendet werden (z. B. wenn Sie zur nächsten Seite wechseln). Dies ist in Ordnung, aber für die aktuelle Seite nicht nützlich! Darüber hinaus geben Browser Prefetch-Ressourcen eine niedrigere Priorität als Preload-Ressourcen - die aktuelle Seite ist wichtiger als die nächste. Weitere Informationen finden Sie unter Link-Vorabruf-FAQ .
  • <link rel="prerender">rendert eine bestimmte Webseite im Hintergrund und beschleunigt das Laden, wenn der Benutzer zu ihr navigiert. Aufgrund der Möglichkeit, die Bandbreite der Benutzer zu verschwenden, behandelt Chrome den Vorrender stattdessen als NoState-Prefetch.
  • <link rel="subresource"> wurde vor einiger Zeit in Chrome unterstützt und sollte das gleiche Problem wie das Vorladen lösen, hatte jedoch ein Problem: Es gab keine Möglichkeit, eine Priorität für die Elemente zu ermitteln (wie es sie damals noch nicht gab), also alle wurde mit ziemlich niedriger Priorität abgeholt.

Es gibt eine Reihe von skriptbasierten Ressourcenladern, aber sie haben keine Macht über die Abrufpriorisierungswarteschlange des Browsers und unterliegen weitgehend denselben Leistungsproblemen.

Quelle: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content

Per Quested Aronsson
quelle
Dies sollte die akzeptierte Antwort sein. Vielen Dank!
Renan Coelho
1

Ich habe eine ähnliche Antwort für das asynchrone Vorladen von Bildern über JS. Das dynamische Laden entspricht dem normalen Laden. Sie werden zwischengespeichert.

Beim Caching können Sie den Browser nicht steuern, aber über den Server einstellen. Wenn Sie eine wirklich frische Ressource bei Bedarf laden müssen, können Sie die Cache-Buster-Technik verwenden , um das Laden einer neuen Ressource zu erzwingen.

Joseph
quelle
1

Ich verwende eine ähnliche Technik zum Lazyload von Bildern, kann aber nicht anders, als zu bemerken, dass Javascript beim ersten Laden nicht auf den Browser-Cache zugreift.

Mein Beispiel:

Ich habe ein rotierendes Banner auf meiner Homepage mit 4 Bildern. Der Schieberegler wartet 2 Sekunden, dann lädt das Javascript das nächste Bild, wartet 2 Sekunden usw.

Diese Bilder haben eindeutige URLs, die sich ändern, wenn ich sie ändere, sodass sie Caching-Header erhalten, die ein Jahr lang im Browser zwischengespeichert werden.

max-age: 31536000, public

Wenn ich jetzt Chrome Devtools öffne und sicherstelle, dass die Option "Cache deaktivieren" nicht aktiv ist, lade ich die Seite zum ersten Mal (nach dem Löschen des Caches) und alle Bilder werden abgerufen und haben den Status 200. Nach einem vollständigen Zyklus aller Bilder im Banner werden die Netzwerkanforderungen gestoppt und die zwischengespeicherten Bilder werden verwendet.

Wenn ich jetzt eine regelmäßige Aktualisierung durchführe oder zu einer Unterseite gehe und zurückklicke, werden die Bilder im Cache anscheinend ignoriert. Ich würde erwarten, dass auf der Registerkarte "Netzwerk" von Chrome devtools eine graue Meldung "aus dem Festplatten-Cache" angezeigt wird. Stattdessen sehe ich, dass die Anforderungen alle zwei Sekunden mit einem grünen Statuskreis anstelle von grau vergehen. Ich sehe, dass Daten übertragen werden, sodass ich den Eindruck habe, dass auf den Cache überhaupt nicht über Javascript zugegriffen wird. Es ruft das Bild einfach jedes Mal ab, wenn die Seite geladen wird.

Jede Anfrage an die Homepage löst also 4 Anfragen aus, unabhängig von der Caching-Richtlinie des Bildes.

In Anbetracht des oben Gesagten und des neuen http2-Standards, den die meisten Webserver und Browser jetzt unterstützen, ist es meiner Meinung nach besser, das Lazyloading zu beenden, da http2 alle Bilder fast gleichzeitig lädt.

Wenn dies ein Fehler in Chrome Devtools ist, überrascht es mich wirklich, dass dies noch niemand bemerkt hat. ;)

Wenn dies zutrifft, erhöht die Verwendung von Lazyloading nur die Bandbreitennutzung.

Bitte korrigieren Sie mich, wenn ich falsch liege. :) :)

Jean-Paul Ladage
quelle
1

Heutzutage gibt es eine neue Technik, die von Google vorgeschlagen wird , um Ihren Bildwiedergabeprozess zwischenzuspeichern und zu verbessern:

  1. Fügen Sie die JavaScript-Datei Lazysizes hinzu: lazysizes.js
  2. Fügen Sie die Datei der HTML-Datei hinzu, die Sie verwenden möchten: <script src="lazysizes.min.js" async></script>
  3. Fügen Sie die lazyloadKlasse Ihrem Bild hinzu: <img data-src="images/flower3.png" class="lazyload" alt="">
Mehdi Bouzidi
quelle
0

Ja, der Browser speichert Bilder automatisch für Sie zwischen.

Sie können jedoch festlegen, dass ein Bildcache abläuft. Schauen Sie sich diese Fragen zum Stapelüberlauf an und beantworten Sie:

Cache-Ablauf bei statischen Bildern

Magzalez
quelle
0

Ich bevorzuge immer das in Konva JS: Image Events erwähnte Beispiel , um Bilder zu laden.

  1. Sie benötigen eine Liste von Bild-URLs als Objekt oder Array, zum Beispiel:

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

  2. Definieren Sie die Funktionsdefinition, in der eine Liste der Bild-URLs und eine Rückruffunktion in der Argumentliste angezeigt werden. Wenn das Laden des Bilds abgeschlossen ist, können Sie die Ausführung auf Ihrer Webseite starten:

    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. Zuletzt müssen Sie die Funktion aufrufen. Sie können es zum Beispiel aus aufrufen jQuery‚s Dokument Bereit

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

Mahdi Alkhatib
quelle