取消 html5 浏览器中的单张图片请求

Posted

技术标签:

【中文标题】取消 html5 浏览器中的单张图片请求【英文标题】:Cancel single image request in html5 browsers 【发布时间】:2011-06-23 00:15:04 【问题描述】:

我正在动态加载(大)图像以绘制到 html5 画布中,如下所示:

var t = new Image();
t.onload = ...
t.src = 'http://myurl';

但每隔一段时间想完全取消图像请求

我想出的唯一方法是将src 设置为''。即

t.src = ''

这适用于许多浏览器,但似乎只有 Firefox 真正取消了对图像的 http 请求。

我使用Fiddler2 对此进行了测试,方法是禁用缓存并启用“模拟调制解调器速度”。然后运行a fiddle to test canceling a image request.(我很想听听其他关于如何测试它的想法)

我知道有办法取消所有请求 (as in this question),但我只想取消一个。

对其他方式(尤其是在移动浏览器上)有什么想法吗?

【问题讨论】:

提防t.src = '',规范对应该发生的事情含糊不清。见nczonline.net/blog/2009/11/30/… 对...一些浏览器正在向页面的 url(或基本 url)发出请求,以尝试使用 src='' 加载图像。在 Firefox 下,设置 t.src=null 也会取消请求,但不会对其他请求执行任何操作。较新的(当前工作)规范说(在某些情况下)it should fire onerror... kindof. 在 Firefox 下设置src 为内联图像也会取消之前的请求:t.src='data:image/gif;base64,R0lGOD... 见this fiddle empty image src 使页面重新加载使您进入页面的请求。因此,当您在发布后到达页面时,浏览器将默默地重做 POST。这确实是一个很好的方式来射击自己。 【参考方案1】:

这是我设法让它在所有现代浏览器(Chrome、Safari、Mobile-Safari、Firefox 和 IE9)中工作的唯一方法。

加载一个空的和隐藏的iframeimage tag 附加到iframe 中的body img.onload 完成后,您可以使用该图像 dom 元素通过drawImage() 绘制到 html5 画布 如果您想取消加载,请在iframecontentWindow 上发出stop()(或在IE 中contentDocument 上发出execCommand("stop", false))。 取消图片加载后,您可以重复使用 iframe 来加载更多图片。

我为此创建了一个类,并将coffeescript 代码(以及已编译的javascript)放在github 上: Cancelable Html5 Image Loader

如果你想玩它,我还创建了一个jsfiddle to test it out。记得启动 Fiddler2(或类似的东西)来查看实际的网络请求是否真的被取消了。

【讨论】:

+1 感谢您的破解。很高兴找到一种方法来为没有画布的旧 IE 版本提供一些东西,也许可以使用在 IE 上添加画布支持的库。 @Amir,我们如何在 openlayers 平铺请求中实现这一点? @Amir 我遇到了同样的问题并尝试复制您的脚本,但我无法让 iframe.contentWindow.stop() 方法工作。有什么办法可以看看吗?【参考方案2】:

您可以尝试 window.stop() 来停止所有请求,但不能停止单个请求。在 IE 中,不是 window.stop(),而是 document.execCommand("Stop", false)。

如果您在请求方面有其他事情要做,那么这样做会干扰它。 (你会跟进重新请求你仍然想要的资源,但这太像辛苦了)。


因此,如果您想停止对大图像的单个请求,您可以将图像加载到隐藏的 IFRAME 内的文档中。 IFRAME 的 onload 事件可用于将图像加载到主文档中,此时它应该被缓存(假设您已经配置了缓存指令)。

如果图像花费的时间过长,那么您可以访问 IFRAME 的 contentWindow 并对其发出停止命令。

您需要拥有与可以同时请求的图像一样多的 IFRAME 元素。

【讨论】:

"但不是个别的"...你能支持一下吗?您提供的其余信息已在问题中说明并链接到。 您只能停止该窗口的所有正在进行的请求。这给了我一个想法,请参阅添加到我的答案中的其他信息!【参考方案3】:

我怀疑是否有一种跨浏览器的方法可以在没有黑客攻击的情况下实现这一点。一个建议是向服务器端脚本发出 AJAX 请求,该脚本返回图像的 Base64 编码版本,然后您可以将其设置为 src 属性。然后,如果您决定取消加载图像,则可以取消此请求。但是,如果您想逐步显示图像,这可能会很困难。

【讨论】:

好主意,但有几个与此相关的问题。首先是传输的数据量增加了 33%。 (base64:24 位 -> 32 位)。然后(特别是在移动浏览器上),它给 javascript 带来了很大的内存压力,因为数据必须在 JS 中存储为字符串,然后它还有一个额外的 base64 解码步骤。对于大文件(200K+),这可能会造成伤害。但这在某些情况下肯定会很好用。 这很好。当我提出这个想法时,我没有考虑开销。显然,在使用 AJAX nagoon97.wordpress.com/2008/04/06/… 读取二进制文件方面已经付出了一些努力。我自己从未尝试过,但您可以这样做,然后使用 <canvas> 绘制图像。【参考方案4】:

其实我也有同样的问题,做了一些测试。

我用 iframes 做了一些测试,并取得了一些成功。在 Firefox 3.6 和 Chrome 上测试。对于测试,我使用了 9 张 15Mb 的图像。使用 img 预加载我多次杀死了我的 firefox(是的,这台计算机上没有太多记忆),如果请求已经开始,使用 img 的“暂停”操作不会阻止图像加载,使用 iframe 的暂停操作真的会停止下载(因为我删除 iframe)。下一步将使用 XMLHttpRequests 进行测试。由于我的测试代码的这个版本使用图像 url 中的 braowser 缓存行为来防止第二次加载,这也适用于 ajax 请求。但也许使用 iframe,我可以找到一种直接从 iframe 中加载的图像中检索二进制数据的方法(限制相同的域 url)。

这是我的测试代码(在 Chrome 上非常快,可能会因为太多非常大的图像而杀死你的 firefox):

// jQuery.imageload.shared.list contains an array of oversized images url
jQuery.each(imglist,function(i,imgsrc) 

    name = 'imageload-frame';
    id = name + "-" + i;
    // with img it is not possible to suspend, the get is performed even after remove
    //var loader = jQuery('<img />').attr('name', name).attr('id',id);
    var loader = jQuery('<iframe />').attr('name', name).attr('id',id); 

    //no cache on GET query taken from jQuery core
    // as we really want to download each image for these tests
    var ts = +new Date;
    // try replacing _= if it is there
    var ret = imgsrc.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
    // if nothing was replaced, add timestamp to the end
    imgsrc = imgsrc + ((ret == imgsrc) ? (imgsrc.match(/\?/) ? "&" : "?") + "_=" + ts : "");

    loader.css('display', 'none').appendTo('body');
    loader.after( jQuery('<a>')
            .text(' stop ')
            .attr('href','#')
            .click(function()
                loader.remove();
                jQuery(this).text(' suspended ');
            )
    );

    // start the load - preload
    loader.attr('src',imgsrc);

    // when preload is done we provide a way to get img in document
    loader.load(function() 
        jQuery(this).next("a:first")
            .text(" retrieve ").unbind('click')
            .click(function() 
                var finalimg = jQuery('<img />');
                // browser cache should help us now
                // but there's maybe a way to get it direclty from the iframe
                finalimg.attr('src',loader[0].src);
                finalimg.appendTo('body');
            );
    );
);

编辑,这里是用来测试它的fillde:http://jsfiddle.net/wPr3x/

【讨论】:

如此接近,但有一个问题。由于某种原因,当图像在 iframe 中加载时,它不会立即在缓存中可用。所以图像最终被加载了两次。这是一个可以玩的小提琴。 jsfiddle.net/amirshim/na3UA 启动 fiddler2(在 PC 上)并查看图像是如何被请求两次的。如果你关闭use_unique_name,那么你会看到图像在整个页面第一次加载后被缓存。 我创建了一个新问题来尝试解决这个问题:***.com/questions/4981229/… 在第一个小提琴示例中,我看不到在设置 src 属性之前和插入 iframe 之后设置 load() 回调的位置。因此,您可能会在“about:blank”等加载之后调用此加载事件,即空 iframe 基本源。 我使用 loader.onload = 而不是 jquery load()。但这里有一个与 jQuery 方法有同样问题的小提琴:jsfiddle.net/amirshim/na3UA/1 正如在另一个问题中所回答的那样,我认为如果你像我一样写它可以工作:-)。这是一个测试它的小提琴,但有时要小心更改图像 url,以防止目标服务器上的 DOS。 jsfiddle.net/wPr3x

以上是关于取消 html5 浏览器中的单张图片请求的主要内容,如果未能解决你的问题,请参考以下文章

Html5中的video标签在微信内置浏览器和QQ浏览器表现的奇怪问题

请问在用html5开发手机相册时,如何去浏览手机中的图片呢可以实现用js浏览手机内存卡中的图片吗谢谢!

取消chrome浏览器下input和textarea的默认样式;html5默认input内容清除“×”按钮去除办法

chrome中的文档/重定向已取消请求问题

html5如何让图片3d旋转

即使浏览器支持 html5 视频,也显示后备图像