后加载:检查图像是否在浏览器缓存中

Mat*_*ieu 27 javascript jquery caching lazy-loading

简短版本问题: 是否有navigator.mozIsLocallyAvailable等效功能适用于所有浏览器,或替代?

长版:)

嗨,这是我的情况:我想为asp.net MVC实现一个HtmlHelper扩展,它可以轻松处理图像后加载(使用jQuery).

所以我使用"alt"属性中指定的源渲染具有空图像源的页面.我在"window.onload"事件之后插入图像源,效果很好.

我做了这样的事情:

$(window).bind('load', function() {
    var plImages = $(".postLoad");
    plImages.each(function() {
        $(this).attr("src", $(this).attr("alt"));
    });
});
Run Code Online (Sandbox Code Playgroud)

问题是:第一次加载后,缓存后加载的图像.但是如果页面加载需要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"));
    });
});
Run Code Online (Sandbox Code Playgroud)

它适用于Mozilla的DOM,但它不适用于任何其他DOM.我试过navigator.isLocallyAvailable:相同的结果.

还有其他选择吗?

Mat*_*ieu 18

经过一番研究,我找到了一个解决方案:

我们的想法是记录缓存的图像,在图像的"加载"事件上绑定日志功能.我首先想过将源存储在cookie中,但如果在没有cookie的情况下清除缓存则不可靠.此外,它还为HTTP请求添加了一个cookie ...

然后我遇到了魔法: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"));
    });
});
Run Code Online (Sandbox Code Playgroud)

  • 我认为这将在缓存过期时中断...您需要在localStorage中存储响应头(这需要ajax调用)的到期日期.例如,logCache中的`localStorage [src] = expires`和缓存中的`now <localStorage [src]`.(显然需要更多的代码;但是你明白了.) (10认同)
  • 如果手动清除缓存会怎样? (2认同)

Dyl*_*xey 11

检查图像是否已缓存的最有效、简单且广泛支持的方法是执行以下操作...

  1. 创建图像对象
  2. 将 src 属性设置为所需的 url
  3. 立即检查completed属性,看看图像是否已经被缓存
  4. 将 src 属性设置回“”(空字符串),这样图像就不会被不必要地加载(除非此时你想粗略地加载它)

就像这样...

function isCached(src) {
    const img = new Image();
    img.src = src;
    const complete = img.complete;
    img.src = "";
    return complete;
}
Run Code Online (Sandbox Code Playgroud)

在你的情况下,它可以像这样实现......

const lazyImages = document.querySelectorAll(".postLoad");
for (const img of lazyImages) {
    if ((!img.src || !isCached(img.src)) && img.getAttribute("alt")) {
        img.src = img.getAttribute("alt");
    }
}
Run Code Online (Sandbox Code Playgroud)

话虽这么说,我建议不要为此目的使用 alt 属性,您应该使用类似的东西data-src


McD*_*McD 5

如果缓存,则几乎立即返回对图像的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;
}
Run Code Online (Sandbox Code Playgroud)