Как вы кешируете изображение в Javascript

84

Мы с друзьями работаем над веб-сайтом, на котором мы хотели бы кэшировать определенные изображения, чтобы отображать их быстрее в будущем. У меня два основных вопроса:

  1. Как вы кешируете изображение?
  2. Как использовать изображение после кеширования? (и просто для проверки, если изображение кэшировано на странице A, его можно вызвать из кеша, чтобы использовать на странице B, верно?)

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

Было бы очень признательно, если бы был включен пример и / или ссылка на страницу, которая описывает это дополнительно.

Мы можем использовать либо необработанный Javascript, либо версию jQuery.

Логан Бесеккер
источник
12
Вы этого не сделаете. Браузер делает.
Pointy
кэширует ли браузер изображения автоматически?
Logan Besecker,
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);
jfriend00
источник
В этом примере вы создаете новый объект 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
Можно ли предварительно загрузить изображение на одну страницу (не отображая его), а затем отобразить на следующей странице?
Logan Besecker,
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
Приятно приятно приятно приятно!
Bhargav Nanekalva
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, который теперь поддерживает большинство веб-серверов и браузеров, я думаю, что лучше отказаться от ленивой загрузки, поскольку http2 загружает все изображения почти одновременно.

Если это ошибка в Chrome Devtools, меня действительно удивляет, что никто этого еще не заметил. ;)

Если это так, использование отложенной загрузки только увеличивает использование полосы пропускания.

Пожалуйста, поправьте меня, если я ошибаюсь. :)

Жан-Поль Лэдаж
источник
1

В настоящее время Google предлагает новую технику для кэширования и улучшения процесса рендеринга изображений:

  1. Включите файл JavaScript Lazysizes: 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«S Document Ready

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

Махди Алхатиб
источник