6

我不想知道预加载图像的方法,我在网上找到了很多,但我想知道它是如何工作的。javascript如何能够预加载图像?我的意思是,我从这里尝试了一个片段,即使它有效,它似乎也没有预加载图像。

当我检查萤火虫时,我可以看到图像被加载了两次,一次是在预加载时,另一次是在显示它时!

为了改进这段代码,我想知道它是如何工作的。

这是我所做的:

 function preload(arrayOfImages) {
        $(arrayOfImages).each(function(){
            $('<img/>')[0].src = this;
            //(new Image()).src = this;
            alert(this +'  &&   ' + i++);

        });
    }

然后我做这样的事情:

preloader = function() {
    preload(myImages);
}

$(document).ready(preloader);

这是我显示/添加图像的方式:

$("li.works").click(function() {
             $("#viewer").children().empty();
             $('#viewer').children().append('<img src=\'images/ref/'+this.firstChild.id+'.jpg\' alt="'+this.firstChild.id+'" \/>')
             $("#viewer").children().fadeIn();
4

5 回答 5

11

您的基本 Javascript 预加载器执行以下操作:

var image = new Image();
image.src = '/path/to/the/image.jpg';

它的工作方式是简单地创建一个新的 Image 对象并设置它的 src,浏览器将去抓取图像。我们不会将这个特定的图像添加到浏览器中,但是当需要通过我们设置的任何方法在页面中显示图像时,浏览器已经将它放在缓存中并且不会再次获取它。但是,如果不查看代码,我真的无法告诉您为什么您所拥有的一切都不能以这种方式工作。

这个问题中讨论的一个有趣的问题是,当您拥有一组图像并尝试使用相同的 Image 对象预加载它们时会发生什么:

var images = ['image1.jpg','image2.jpg'];
var image = new Image();
for(var x = 0; x < images.length; x++) {
    image.src = images[x];
}

这只会预加载最后一个图像,因为在循环再次出现以更改对象的源之前,其余图像将没有时间进行预加载。查看一个例子。单击按钮后,您应该能够立即看到第二张图像,但必须加载第一个图像,因为当您尝试查看它时它没有机会预加载。

因此,一次做很多事情的正确方法是:

var images = ['image1.jpg','image2.jpg'];
for(var x = 0; x < images.length; x++) {
    var image = new Image();
    image.src = images[x];
}
于 2009-05-13T23:31:27.283 回答
5

Javascript 预加载通过利用浏览器使用的缓存机制来工作。

其基本思想是,一旦资源被下载,它会在客户端机器上本地存储一段时间,这样浏览器就不必再次从网络上检索资源,下次需要显示时/由浏览器使用。

您的代码可能运行良好,而您只是误解了 Fire Bug 显示的内容。

要测试这个理论,只需使用干净的缓存访问 www.google.com。即首先清除您的下载历史记录。

第一次通过一切可能会有 200 OK 的状态。这意味着您的浏览器请求了资源并且服务器发送了它。如果您查看 Fire Bug 窗口的底部,它会显示页面有多大,例如 195Kb 以及从缓存中提取了多少。在这种情况下为 0Kb。

然后在不清除缓存的情况下重新加载相同的页面,您仍然会在 FireBug 中看到相同数量的请求。

原因很简单。页面没有改变,仍然需要它以前需要的所有相同资源。

不同的是,对于这些请求中的大多数,服务器返回 304 Not Modified 状态,因此浏览器检查它的缓存以查看它是否已经在本地存储了资源,在这种情况下,它是从上一个页面加载开始的。所以浏览器只是从本地缓存中提取资源。

如果您查看 Fire Bug 窗口的底部,您将看到页面大小仍然相同(195Kb),但其中大部分(在我的情况下为 188Kb)是从本地缓存中提取的。

所以缓存确实起作用了,我第二次点击谷歌时,我节省了 188Kb 的下载量。

我相信你会在预加载图像时发现同样的事情。请求仍在发出,但如果服务器返回 304 状态,那么您将看到图像实际上只是从本地缓存中提取的,而不是从网络中提取的。

因此,使用缓存的好处不是您终止所有未来的资源请求,即仍然对网络进行 Uri 查找,而是如果可能,浏览器将从本地缓存中提取以满足对内容的需求,而不是跑遍网络寻找它。

于 2011-10-08T10:11:30.353 回答
2

您可能对“预加载”的概念感到困惑。如果你的 HTML 中有一堆图片<img src="...">,它们不能用 Javascript 预加载,它们只是随页面一起加载。

使用 Javascript 预加载图像是关于加载尚未在文档源中的图像,然后再显示它们。它们在页面第一次呈现后加载。它们被预加载是为了在使它们出现时消除/最小化加载时间,例如在鼠标悬停时更改图像时。

对于大多数应用程序,使用“CSS sprites”作为一种预加载形式来代替 Javascript 通常是更好的做法。SO应该对此有很多问题。

于 2009-05-14T00:06:19.160 回答
1

它只涉及制作一个新的 DOM 图像对象并设置src属性。没有什么聪明和AFAIK,它一直对我有用。

是否有可能第二个“加载”萤火虫向您显示它是从缓存中加载的吗?

于 2009-05-13T23:31:53.150 回答
1

循环上的索引只查看第一张图像。将其更改为使用索引:

function preload(arrayOfImages) {
    $(arrayOfImages).each(function(i){   // Note the argument
        $('<img/>')[i].src = this;    // Note the i
        //(new Image()).src = this;
        alert(this +'  &&   ' + i++);

    });
}

编辑:回想起来,这是错误的,我可以看到您正在尝试创建图像元素。我不明白为什么索引在那里,不需要索引。我认为函数应该是这样的:

function preload(arrayOfImages) {
    $(arrayOfImages).each(function () {
        $('<img/>').attr('src', this);
    });
}    

为了实例化它,为什么不这样做:

$(function () {    // Equivalent to $(document).ready()
    preload(myImages);
});

JavaScript 图像预加载之所以有效,是因为在创建包含图像的 DOM 元素时,会下载并缓存该图像。即使在实际从 HTML 呈现图像时发出另一个请求,服务器也会发回 304(未更改),并且浏览器将简单地从其缓存中加载图像。

Paolo 建议使用以下符号来创建图像对象:

var image = new Image();

虽然这会起作用,但符合 DOM 的方法是:

var image = document.createElement('img');
image.setAttribute('src', 'path/to/image.jpg');

这是在脚本中完成的方式,除了它使用 jQuery 的 HTML 字符串文字语法来完成它。Image()此外,大多数现代浏览器通过简单地调用 DOM 标准方法来提供与构造函数的兼容性。例如,如果您打开 Google Chrome JavaScript 控制台并输入Image,您将获得以下信息:

function Image() {
    return document.createElementNS('http://www.w3.org/1999/xhtml', 'img');
}

Chrome 仅使用原生 DOM 方法来创建图像元素。

于 2009-05-13T23:53:09.307 回答