Постзагрузка: проверьте, находится ли изображение в кеше браузера

Короткая версия вопроса: существует ли эквивалентная функция 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"));
    });
});

Наиболее эффективный, простой и широко поддерживаемый способ проверки того, что изображение уже было кэшировано, заключается в следующем:

  1. Создать изображение объекта
  2. Установите для свойства src желаемый URL
  3. Немедленно проверьте заполненный атрибут, чтобы увидеть, кэшировано ли уже изображение
  4. Установите для атрибута 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}
    />
  )
}
Другие вопросы по тегам