¿Cómo se almacena en caché una imagen en Javascript?


83

Mis amigos y yo estamos trabajando en un sitio web donde nos gustaría almacenar en caché ciertas imágenes para mostrarlas más rápido en el futuro. Tengo dos preguntas principales:

  1. ¿Cómo se almacena en caché una imagen?
  2. ¿Cómo se usa una imagen una vez que se ha almacenado en caché? (y solo para verificar, si una imagen está almacenada en caché en la página A, es posible llamarla desde la caché para usarla en la página B, ¿verdad?)

Además, ¿es posible establecer cuándo caducará la versión en caché de la imagen?

Se agradecería mucho si se incluyera un ejemplo y / o un enlace a una página que describa esto con más detalle.

Estamos bien usando Javascript sin formato o la versión jQuery.


12
Tu no El navegador lo hace.
Puntiagudo

¿El navegador almacena en caché las imágenes automáticamente?
Logan Besecker

8
@Logan: Sí, el navegador almacena imágenes en caché automáticamente, siempre que su servidor envíe los encabezados necesarios para indicarle al navegador que es seguro almacenarlas en caché. (Estos encabezados también pueden indicarle al navegador el tiempo de vencimiento, que es parte de su pregunta).
icktoofay

¿Cómo puedo verificar que mi navegador envía los encabezados necesarios?
Logan Besecker

1
@LoganBesecker Puede comprobar los encabezados de respuesta en la sección Red de las herramientas de desarrollo de su navegador.
jlaceda

Respuestas:


131

Una vez que una imagen se ha cargado de alguna manera en el navegador, estará en la caché del navegador y se cargará mucho más rápido la próxima vez que se use, ya sea que ese uso sea en la página actual o en cualquier otra página, siempre que la imagen sea utilizado antes de que expire de la caché del navegador.

Por lo tanto, para almacenar en caché las imágenes, todo lo que tiene que hacer es cargarlas en el navegador. Si desea almacenar en caché un montón de imágenes, probablemente sea mejor hacerlo con javascript, ya que generalmente no retendrá la carga de la página cuando se hace desde javascript. Puedes hacerlo así:

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

Esta función se puede llamar tantas veces como desee y cada vez, solo agregará más imágenes al precaché.

Una vez que las imágenes se han precargado de esta manera a través de javascript, el navegador las tendrá en su caché y usted puede simplemente consultar las URL normales en otros lugares (en sus páginas web) y el navegador obtendrá esa URL de su caché en lugar de hacerlo a través del red.

Eventualmente, con el tiempo, el caché del navegador puede llenarse y deshacerse de las cosas más antiguas que no se han usado por un tiempo. Entonces, eventualmente, las imágenes se borrarán del caché, pero deberían permanecer allí por un tiempo (dependiendo de qué tan grande sea el caché y cuántas otras búsquedas se realicen). Cada vez que las imágenes se precargan de nuevo o se utilizan en una página web, actualiza su posición en la caché del navegador automáticamente para que sea menos probable que se vacíen de la caché.

La caché del navegador es entre páginas, por lo que funciona para cualquier página cargada en el navegador. Por lo tanto, puede almacenar previamente en un lugar de su sitio y la caché del navegador funcionará para todas las demás páginas de su sitio.


Al almacenar en caché como se indicó anteriormente, las imágenes se cargan de forma asincrónica para que no bloqueen la carga o visualización de su página. Pero, si su página tiene muchas imágenes propias, estas imágenes precaché pueden competir por ancho de banda o conexiones con las imágenes que se muestran en su página. Normalmente, este no es un problema notable, pero en una conexión lenta, este almacenamiento en caché podría ralentizar la carga de la página principal. Si estaba bien que las imágenes de precarga se cargaran en último lugar, entonces podría usar una versión de la función que esperaría para iniciar la precarga hasta que todos los demás recursos de la página ya estuvieran cargados.

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

En este ejemplo, está creando un nuevo objeto de imagen para cada URL. Si configura la variable img fuera del ciclo y simplemente actualiza el src, debería tener el mismo efecto y reducir los recursos
cadlac

1
@cadlac - Pero para estar seguro de que el navegador descargaría y almacenaría en caché cada imagen, tendría que esperar hasta que una imagen terminara de descargarse antes de establecer una nueva propiedad .src. De lo contrario, el navegador podría detener la descarga anterior y nunca almacenarla en caché.
jfriend00

Parece funcionar en versiones más nuevas de navegadores sin esperar, pero tiene un buen punto. Tendré que probarlo en algunos navegadores más antiguos para ver su compatibilidad :)
cadlac

@cadlac: no es necesario. Actualicé el código para eliminar el Image()elemento de la lista cuando la imagen termina de cargarse. Es más seguro esperar hasta que la imagen haya terminado de cargarse.
jfriend00

1
Agregué otra versión del script que espera hasta que se hayan cargado otros recursos del documento para que la precarga de imágenes no compita por el ancho de banda con la carga de los recursos de la página visible.
jfriend00

13

como @Pointy dijo que no almacena imágenes en caché con javascript, el navegador lo hace. así que esto puede ser lo que estás pidiendo y puede que no lo sea ... pero puedes precargar imágenes usando javascript. Al colocar todas las imágenes que desea precargar en una matriz y colocar todas las imágenes de esa matriz en elementos img ocultos, efectivamente precarga (o almacena en caché) las imágenes.

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

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

2
¿Sería posible precargar una imagen en una página (sin mostrarla) y luego mostrarla en la página siguiente?
Logan Besecker

2
Que yo sepa, si carga previamente una imagen en una página, se ingresará en la caché de los navegadores y luego se mostrará más rápido en cualquier otra página. si esto está mal, alguien me corrija.
Trav McKinney

3

Hay algunas cosas que puede ver:

Cargar previamente sus imágenes
Establecer un tiempo de caché en un archivo .htaccess Tamaño de
archivo de imágenes y codificarlas en base64.

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

Almacenamiento en caché: http://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html

Hay un par de ideas diferentes para la codificación base64, algunos dicen que las solicitudes http atascan el ancho de banda, mientras que otros dicen que la carga "percibida" es mejor. Dejaré esto en el aire.


3

Aunque su pregunta dice "usando javascript", puede usar el prefetchatributo de una etiqueta de enlace para precargar cualquier activo. En el momento de escribir este artículo (10 de agosto de 2016) no es compatible con Safari, pero está prácticamente en cualquier otro lugar:

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

Más información sobre soporte aquí: http://caniuse.com/#search=prefetch

Tenga en cuenta que IE 9,10 no se enumeran en la caniusematriz porque Microsoft ha descontinuado el soporte para ellos.

Entonces, si estaba realmente atascado en el uso de JavaScript, también podría usar jquery para agregar dinámicamente estos elementos a su página ;-)


1
Agradable agradable agradable agradable!
Bhargav Nanekalva

2

Agregar para completar las respuestas: precarga con HTML

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

Existen otras características de precarga, pero ninguna es tan adecuada para su propósito como <link rel="preload">:

  • <link rel="prefetch">ha sido compatible con los navegadores durante mucho tiempo, pero está destinado a la obtención previa de recursos que se utilizarán en la siguiente navegación / carga de página (por ejemplo, cuando vaya a la página siguiente). Esto está bien, ¡pero no es útil para la página actual! Además, los navegadores darán menos prioridad a los recursos de captación previa que a los de precarga: la página actual es más importante que la siguiente. Consulte Preguntas frecuentes sobre la obtención previa de enlaces para obtener más detalles.
  • <link rel="prerender">renderiza una página web específica en segundo plano, acelerando su carga si el usuario navega hacia ella. Debido al potencial de desperdiciar el ancho de banda de los usuarios, Chrome trata el procesamiento previo como una captura previa NoState.
  • <link rel="subresource"> era compatible con Chrome hace un tiempo, y estaba destinado a abordar el mismo problema que la precarga, pero tenía un problema: no había forma de determinar una prioridad para los elementos (ya que no existía en ese entonces), por lo que todos fue recuperado con una prioridad bastante baja.

Hay varios cargadores de recursos basados ​​en scripts, pero no tienen ningún poder sobre la cola de priorización de búsqueda del navegador y están sujetos a los mismos problemas de rendimiento.

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


Esta debería ser la respuesta aceptada. ¡Gracias!
Renan Coelho

1

Tengo una respuesta similar para imágenes de precarga asíncrona a través de JS. Cargarlos dinámicamente es lo mismo que cargarlos normalmente. almacenarán en caché.

en cuanto al almacenamiento en caché, no puede controlar el navegador, pero puede configurarlo a través del servidor. Si necesita cargar un recurso realmente nuevo bajo demanda, puede usar la técnica de cachebuster para forzar la carga de un recurso nuevo.


1

Utilizo una técnica similar para cargar imágenes de forma diferida, pero no puedo evitar notar que Javascript no accede al caché del navegador en la primera carga.

Mi ejemplo:

Tengo un banner giratorio en mi página de inicio con 4 imágenes, el control deslizante espera 2 segundos, luego el javascript carga la siguiente imagen, espera 2 segundos, etc.

Estas imágenes tienen URL únicas que cambian cada vez que las modifico, por lo que obtienen encabezados de almacenamiento en caché que se almacenarán en el navegador durante un año.

max-age: 31536000, public

Ahora, cuando abro Chrome Devtools y me aseguro de que la opción 'Desactivar caché' no esté activa y cargo la página por primera vez (después de borrar la caché), todas las imágenes se recuperan y tienen un estado 200. Después de un ciclo completo de todas las imágenes en el banner, las solicitudes de red se detienen y se utilizan las imágenes en caché.

Ahora, cuando realizo una actualización regular o voy a una subpágina y hago clic en Atrás, las imágenes que están en el caché parecen ignorarse. Esperaría ver un mensaje gris "desde la memoria caché del disco" en la pestaña Red de las herramientas de desarrollo de Chrome. En cambio, veo que las solicitudes pasan cada dos segundos con un círculo de estado verde en lugar de gris, veo que se transfieren datos, por lo que tengo la impresión de que no se accede a la caché desde javascript. Simplemente obtiene la imagen cada vez que se carga la página.

Entonces, cada solicitud a la página de inicio desencadena 4 solicitudes independientemente de la política de almacenamiento en caché de la imagen.

Teniendo en cuenta lo anterior en conjunto y el nuevo estándar http2 que la mayoría de los navegadores y servidores web ahora admiten, creo que es mejor dejar de usar la carga diferida ya que http2 cargará todas las imágenes casi simultáneamente.

Si esto es un error en Chrome Devtools, realmente sorprende que nadie lo haya notado todavía. ;)

Si esto es cierto, el uso de la carga diferida solo aumenta el uso del ancho de banda.

Por favor corrígeme si estoy equivocado. :)



0

Siempre prefiero usar el ejemplo mencionado en Konva JS: Image Events para cargar imágenes.

  1. Necesita tener una lista de URL de imagen como objeto o matriz, por ejemplo:

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

  2. Defina la definición de la función, donde recibe la lista de URL de la imagen y una función de devolución de llamada en su lista de argumentos, para que cuando termine de cargar la imagen, pueda comenzar a excutar en su página 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. Por último, debe llamar a la función. Puede llamarlo, por ejemplo, desde jQuery's Document Ready

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


0

Hoy en día, hay una nueva técnica sugerida por Google para almacenar en caché y mejorar su proceso de representación de imágenes:

  1. Incluya el archivo JavaScript Lazysizes: lazysizes.js
  2. Agregue el archivo al archivo html que desea usar en: <script src="lazysizes.min.js" async></script>
  3. Agrega la lazyloadclase a tu imagen: <img data-src="images/flower3.png" class="lazyload" alt="">
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.