Як кешувати зображення в Javascript


84

Ми з друзями працюємо над веб-сайтом, де ми хотіли б кешувати певні зображення, щоб швидше відображати їх у майбутньому. У мене є два основних питання:

  1. Як кешувати зображення?
  2. Як використовувати зображення після кешування? (і просто для перевірки, якщо зображення кешоване на сторінці A, можна викликати його з кешу, щоб використовувати його на сторінці B, так?)

Крім того , можна встановити , коли в кеші версія зображення закінчується?

Буде дуже вдячно, якщо буде включено приклад та / або посилання на сторінку, яка описує це далі.

Ми добре використовуємо або необроблений Javascript, або версію jQuery.


12
Ти ні. Браузер робить.
Пойнті

браузер кешує зображення автоматично?
Логан Безекер,

8
@Logan: Так, браузер автоматично кешує зображення, за умови, що ваш сервер надсилає необхідні заголовки, щоб повідомити браузеру про безпеку кешування. (Ці заголовки можуть також повідомляти браузеру час закінчення терміну дії, що є частиною вашого запитання.)
icktoofay

як я можу перевірити, що мій браузер надсилає необхідні заголовки?
Логан Бесекер,

1
@LoganBesecker Ви можете перевірити заголовки відповідей у ​​розділі Мережа інструментів розробника ваших браузерів.
jlaceda

Відповіді:


133

Після того, як зображення будь-яким чином було завантажено в браузер, воно буде знаходитися в кеші браузера і завантажуватиметься набагато швидше під час наступного використання, незалежно від того, чи є це використання на поточній або будь-якій іншій сторінці, доки зображення є використовується до закінчення терміну дії з кешу браузера.

Отже, для попереднього кешування зображень потрібно лише завантажити їх у браузер. Якщо ви хочете попередньо кешувати купу зображень, напевно, найкраще це робити за допомогою JavaScript, оскільки це, як правило, не затримує завантаження сторінки, коли це робиться з javascript. Ви можете зробити це так:

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

Цю функцію можна викликати скільки завгодно разів, і кожного разу вона просто додаватиме більше зображень до попереднього кешу.

Як тільки зображення будуть попередньо завантажені через javascript, браузер буде мати їх у своєму кеші, і ви можете просто посилатися на звичайні URL-адреси в інших місцях (на ваших веб-сторінках), і браузер буде отримувати цю URL-адресу зі свого кешу, а не над мережі.

Згодом кеш браузера може заповнитись і викинути найдавніші речі, які не використовувались деякий час. Зрештою, зображення будуть видалятися з кешу, але вони повинні залишатися там деякий час (залежно від того, наскільки великий кеш і скільки інших переглядів зроблено). Щоразу, коли зображення насправді попередньо завантажуються повторно або використовуються на веб-сторінці, це автоматично оновлює їхнє місце в кеші браузера, тому вони з меншою ймовірністю виводяться з кешу.

Кеш браузера є міжсторінковим, тому він працює для будь-якої сторінки, завантаженої в браузер. Таким чином, ви можете попередньо кешувати в одному місці вашого сайту, а кеш браузера буде працювати для всіх інших сторінок вашого сайту.


Під час попереднього кешування, як зазначено вище, зображення завантажуються асинхронно, щоб вони не блокували завантаження або відображення вашої сторінки. Але якщо на вашій сторінці багато власних зображень, ці зображення попереднього кешу можуть конкурувати за пропускну здатність або зв’язок із зображеннями, які відображаються на вашій сторінці. Зазвичай це не помітна проблема, але при повільному з'єднанні це попереднє кешування може уповільнити завантаження головної сторінки. Якщо для попереднього завантаження зображень останнє завантаження було нормальним, ви можете використовувати версію функції, яка буде чекати початку попереднього завантаження, поки не будуть завантажені всі інші ресурси сторінки.

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

У цьому прикладі ви створюєте новий об'єкт Image для кожної URL-адреси. Якщо ви встановите змінну img за межами циклу і просто оновите src, вона повинна мати такий же ефект і скоротити ресурси
cadlac

2
@cadlac - Але щоб бути впевненим, що браузер насправді буде завантажувати та кешувати кожне зображення, вам доведеться почекати, поки одне зображення завершиться завантаження, перш ніж встановлювати нову властивість .src. В іншому випадку браузер може просто зупинити попереднє завантаження і ніколи не успішно кешувати його.
jfriend00

Здається, це працює на новіших версіях браузерів, не чекаючи, але ви робите хороший момент. Мені доведеться випробувати його на деяких старих браузерах, щоб перевірити, чи це сумісність :)
cadlac

@cadlac - не потрібно. Я оновив код, щоб видалити Image()елемент зі списку, коли зображення закінчується завантаженням. Безпечніше чекати, поки зображення закінчиться завантаження.
jfriend00

1
Я додав іншу версію сценарію, яка чекає, поки завантажаться інші ресурси документа, тому попереднє завантаження зображень не конкурує за пропускну здатність із завантаженням ресурсів видимої сторінки.
jfriend00

13

як @Pointy сказав, що ви не кешуєте зображення за допомогою JavaScript, це робить браузер. отже, це може бути те, про що ви просите, а може і не бути ... але ви можете попередньо завантажити зображення за допомогою JavaScript. Помістивши всі зображення, які потрібно попередньо завантажити, у масив, а всі зображення цього масиву - у приховані елементи img, ви фактично попередньо завантажуєте (або кешуєте) зображення.

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

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

2
чи можна було б попередньо завантажити зображення на одну сторінку (без його відображення), а потім відобразити на наступній сторінці?
Логан Безекер,

2
наскільки мені відомо, якщо ви попередньо завантажите зображення на одну сторінку, воно буде введено в кеш браузера, а потім швидше відображатиметься на будь-якій іншій сторінці. якщо це неправильно, хтось, будь ласка, виправте мене.
Trav McKinney

4

Незважаючи на те, що у вашому запитанні сказано "використання javascript", ви можете використовувати prefetchатрибут тегу посилання для попереднього завантаження будь-якого ресурсу. На момент написання статті (10 серпня 2016 р.) Він не підтримується в Safari, але майже в усьому іншому:

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

Більше інформації про підтримку тут: http://caniuse.com/#search=prefetch

Зверніть увагу, що IE 9,10 не вказано в caniuseматриці, оскільки Microsoft припинила підтримку для них.

Отже, якщо ви справді застрягли у використанні javascript, ви можете використовувати jquery для динамічного додавання цих елементів на свою сторінку ;-)


1
Nice nice nice nice!
Бхаргав Нанекалва,

3

Є кілька речей, на які ви можете подивитися:

Попередня завантаження зображень
Встановлення часу кешування у файлі .htaccess
Розмір файлу зображень та кодування base64.

Попереднє завантаження: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/

Кешування: http://www.askapache.com/htaccess/speed-up-sites-with-htaccess-caching.html

Існує кілька різних думок щодо кодування base64, деякі кажуть, що запити http загрожують пропускною здатністю, а інші кажуть, що "сприймане" завантаження краще. Я залишу це в повітрі.


3

Додавання для повноти відповідей: попереднє завантаження HTML

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

Існують інші функції попереднього завантаження, але жодна не є настільки придатною для цілей, як <link rel="preload">:

  • <link rel="prefetch">підтримується браузерами вже давно, але він призначений для попереднього завантаження ресурсів, які будуть використані при наступній навігації / завантаженні сторінки (наприклад, при переході на наступну сторінку). Це добре, але це не корисно для поточної сторінки! Крім того, браузери надаватимуть ресурсам попередньої вибірки нижчий пріоритет, ніж попередньо завантажені - поточна сторінка важливіша за наступну. Докладніше див. У розділі поширених запитань про попереднє отримання посилань .
  • <link rel="prerender">відображає вказану веб-сторінку у фоновому режимі, прискорюючи її завантаження, якщо користувач переходить до неї. Через можливість втратити пропускну спроможність користувачів, Chrome розглядає попереднє відтворення як попереднє завантаження NoState.
  • <link rel="subresource"> був підтриманий у Chrome деякий час тому і мав на меті вирішити ту ж проблему, що і попереднє завантаження, але у нього була проблема: не було можливості визначити пріоритет для елементів (як тоді ще не існувало), тому всі вони отримано з досить низьким пріоритетом.

Існує ряд завантажувачів ресурсів на основі сценаріїв, але вони не мають жодних повноважень над чергою встановлення пріоритетів для вибору браузера і мають такі ж проблеми з продуктивністю.

Джерело: https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content


1

Я маю подібну відповідь щодо асинхронного попереднього завантаження зображень через JS. Динамічне завантаження - те саме, що звичайне завантаження. вони будуть кешувати.

що стосується кешування, ви не можете керувати браузером, але ви можете встановити його через сервер. якщо вам потрібно завантажити справді свіжий ресурс на вимогу, ви можете використовувати техніку кешування кешу, щоб змусити завантажити новий ресурс.


1

Я використовую подібний прийом для відкладеного завантаження зображень, але не можу не помітити, що Javascript не отримує доступ до кешу браузера при першому завантаженні.

Мій приклад:

У мене на домашній сторінці є обертовий банер із 4 зображеннями, повзунок чекає 2 секунди, тоді як javascript завантажує наступне зображення, чекає 2 секунди тощо.

Ці зображення мають унікальні URL-адреси, які змінюються щоразу, коли я їх модифікую, тому вони отримують заголовки кешування, які кешуються в браузері протягом року.

max-age: 31536000, public

Тепер, коли я відкриваю Chrome Devtools і переконуюсь, що параметр «Вимкнути кеш» неактивний, і завантажую сторінку вперше (після очищення кешу), всі зображення отримують і мають статус 200. Після повного циклу всіх зображень у банері мережеві запити зупиняються і використовуються кешовані зображення.

Тепер, коли я регулярно оновлюю або переходжу на підсторінку та натискаю назад, зображення, що знаходяться в кеші, здається, ігноруються. Я очікував би побачити сіре повідомлення "з кешу диска" на вкладці Мережа Chrome devtools. Натомість я бачу, як запити проходять кожні дві секунди із зеленим колом стану замість сірого, я бачу, як передаються дані, тому складається враження, що кеш взагалі не доступний з javascript. Він просто отримує зображення кожного разу, коли сторінка завантажується.

Отже, кожен запит на домашню сторінку ініціює 4 запити незалежно від політики кешування зображення.

Беручи до уваги вищевикладене та новий стандарт http2, який зараз підтримує більшість веб-серверів та браузерів, я думаю, що краще припинити використання lazyloading, оскільки http2 завантажує всі зображення майже одночасно.

Якщо це помилка в Chrome Devtools, це справді дивує, що цього ще ніхто не помічав. ;)

Якщо це правда, використання lazyloading лише збільшує пропускну здатність.

Будь ласка, виправте мене, якщо я помиляюся. :)


1

У наш час Google пропонує нову техніку для кешування та вдосконалення процесу візуалізації зображень:

  1. Включіть файл Lazysizes JavaScript: lazysizes.js
  2. Додайте файл у файл html, який ви хочете використовувати: <script src="lazysizes.min.js" async></script>
  3. Додайте lazyloadклас до свого зображення: <img data-src="images/flower3.png" class="lazyload" alt="">


0

Я завжди вважаю за краще використовувати приклад, згаданий у Konva JS: Image Events для завантаження зображень.

  1. Вам потрібно мати список URL-адрес зображення як об’єкт або масив, наприклад:

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

  2. Визначте визначення функції, де воно отримує список URL-адрес зображень та функцію зворотного виклику у своєму списку аргументів, тому, коли він закінчує завантаження зображення, ви можете розпочати виконання на вашій веб-сторінці:

    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. Нарешті, вам потрібно викликати функцію. Ви можете зателефонувати йому, наприклад, із jQuery" Document Ready"

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.