Постзагрузка: проверьте, находится ли изображение в кеше браузера
Короткая версия вопроса: существует ли эквивалентная функция navigator.mozIsLocallyAvailable, которая работает во всех браузерах, или альтернатива?
Длинная версия:)
Привет, вот моя ситуация: я хочу реализовать расширение HtmlHelper для asp.net MVC, которые легко обрабатывают пост-загрузку изображения (используя jQuery).
Поэтому я рендерил страницу с пустыми источниками изображений с источником, указанным в атрибуте "alt". Я вставляю источники изображений после события "window.onload", и это прекрасно работает.
Я сделал что-то вроде этого:
$(window).bind('load', function() {
var plImages = $(".postLoad");
plImages.each(function() {
$(this).attr("src", $(this).attr("alt"));
});
});
Проблема заключается в следующем: после первой загрузки пост-загруженные изображения кэшируются. Но если загрузка страницы занимает 10 секунд, кэшированные изображения после загрузки будут отображаться через 10 секунд.
Поэтому я думаю указать источники изображения для события "document.ready", если изображение кэшируется для немедленного их отображения.
Я нашел эту функцию: navigator.mozIsLocallyAvailable, чтобы проверить, находится ли изображение в кеше. Вот что я сделал с jquery:
//specify cached image sources on dom ready
$(document).ready(function() {
var plImages = $(".postLoad");
plImages.each(function() {
var source = $(this).attr("alt")
var disponible = navigator.mozIsLocallyAvailable(source, true);
if (disponible)
$(this).attr("src", source);
});
});
//specify uncached image sources after page loading
$(window).bind('load', function() {
var plImages = $(".postLoad");
plImages.each(function() {
if ($(this).attr("src") == "")
$(this).attr("src", $(this).attr("alt"));
});
});
Он работает на DOM Mozilla, но не работает ни на одном другом. Я попробовал navigator.isLocallyAvailable: тот же результат.
Есть ли альтернатива?
7 ответов
После некоторого поиска я нашел решение:
Идея состоит в том, чтобы регистрировать кэшированные изображения, привязывая функцию регистрации к событию загрузки изображений. Сначала я подумал о том, чтобы хранить исходники в куки, но это ненадежно, если кеш очищается без куки. Более того, он добавляет еще один cookie в HTTP-запросы...
Тогда я встретил волшебство: window.localStorage ( подробности)
Атрибут localStorage обеспечивает постоянные области хранения для доменов
Именно то, что я хотел:). Этот атрибут стандартизирован в HTML5, и он уже работает практически во всех последних браузерах (FF, Opera, Safari, IE8, Chrome).
Вот код (без обработки несовместимых с window.localStorage браузеров):
var storage = window.localStorage;
if (!storage.cachedElements) {
storage.cachedElements = "";
}
function logCache(source) {
if (storage.cachedElements.indexOf(source, 0) < 0) {
if (storage.cachedElements != "")
storage.cachedElements += ";";
storage.cachedElements += source;
}
}
function cached(source) {
return (storage.cachedElements.indexOf(source, 0) >= 0);
}
var plImages;
//On DOM Ready
$(document).ready(function() {
plImages = $(".postLoad");
//log cached images
plImages.bind('load', function() {
logCache($(this).attr("src"));
});
//display cached images
plImages.each(function() {
var source = $(this).attr("alt")
if (cached(source))
$(this).attr("src", source);
});
});
//After page loading
$(window).bind('load', function() {
//display uncached images
plImages.each(function() {
if ($(this).attr("src") == "")
$(this).attr("src", $(this).attr("alt"));
});
});
Наиболее эффективный, простой и широко поддерживаемый способ проверки того, что изображение уже было кэшировано, заключается в следующем:
- Создать изображение объекта
- Установите для свойства src желаемый URL
- Немедленно проверьте заполненный атрибут, чтобы увидеть, кэшировано ли уже изображение
- Установите для атрибута src значение "" или оставьте пустым, чтобы изображение не загружалось без необходимости
Вот так...
function is_cached(src) {
var img = new Image();
img.src = src;
var complete = img.complete;
img.src = "";
return complete;
}
Ajax-запрос к изображению вернется почти сразу, если он будет кэширован. Затем используйте setTimeout, чтобы определить, не готов ли он, и отмените запрос, чтобы вы могли запросить его позже.
Обновить:
var lqueue = [];
$(function() {
var t,ac=0;
(t = $("img")).each(
function(i,e)
{
var rq = $.ajax(
{
cache: true,
type: "GET",
async:true,
url:e.alt,
success: function() { var rq3=rq; if (rq3.readyState==4) { e.src=e.alt; } },
error: function() { e.src=e.alt; }
});
setTimeout(function()
{
var k=i,e2=e,r2=rq;
if (r2.readyState != 4)
{
r2.abort();
lqueue.push(e2);
}
if (t.length==(++ac)) loadRequeue();
}, 0);
}
);
});
function loadRequeue()
{
for(var j = 0; j < lqueue.length; j++) lqueue[j].src=lqueue[j].alt;
}
У меня есть замечание о ваших пустых источниках изображений. Вы написали:
Поэтому я рендерил страницу с пустыми источниками изображений с источником, указанным в атрибуте "alt". Я вставляю источники изображений после события "window.onload", и это прекрасно работает.
Я сталкивался с проблемами в прошлом, потому что в некоторых браузерах пусто src
атрибуты вызывают дополнительные запросы. Вот что они делают (скопировано из правил производительности Yahoo!, есть также пост в блоге по этому вопросу с более подробной информацией):
- Internet Explorer делает запрос в каталог, в котором находится страница.
- Safari и Chrome делают запрос на саму страницу.
- Firefox 3 и более ранние версии ведут себя так же, как Safari и Chrome, но версия 3.5 устранила эту проблему [ошибка 444931] и больше не отправляет запрос.
- Opera ничего не делает, когда встречается пустое изображение src.
Мы также используем много jQuery на нашем сайте, и не всегда было возможно избежать пустых тегов изображений. Я решил использовать прозрачный GIF размером 1x1 px примерно так: src="t.gif"
для изображений, которые я вставляю только после загрузки страницы. Он очень маленький и кэшируется браузером. Это сработало очень хорошо для нас.
Ура, Оливер
На тот случай, если другие могут столкнуться с той же проблемой. некоторые из представленных здесь решений (а именно хранение информации о кеше в локальном хранилище данных браузера) могут сломаться по двум причинам. Во-первых, если срок действия кэша изображения истек, и, во-вторых, если он очищен пользователем. Другой подход - установить источник изображения в качестве заполнителя. Затем измените источник на путь / имя изображения. Таким образом, браузер несет ответственность за проверку собственного кэша. Должно работать с большинством браузеров независимо от их API.
В 2017 году Resource Timing API может помочь вам проверить это с помощью свойства PerformanceResourceTiming.transferSize. Это свойство должно возвращать ненулевой размер передачи, когда оно загружено с сервера (не кэшировано), и возвращает ноль, если оно выбрано из локального кэша.
Ссылка: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/transferSize
Для тех, кто может попытаться решить эту проблему с помощью React, я использовал
complete
свойство изображения, чтобы решить его в React следующим образом:
import React, { useState, useEffect, useRef } from 'react'
const Component= () => {
const [isLoadedImage, setLoadedImage] = useState(false)
const imageRef = useRef(null)
useEffect(() => {
const imgEl = imageRef.current
if (imgEl && imgEl.complete && !isLoadedImage) setLoadedImage(true)
})
return (
<img
onLoad={() => (!isLoadedImage ? setLoadedImage(true) : null)}
ref={imageRef}
/>
)
}