是否应该立即将图像SRC设置为数据URL?
-
23-10-2019 - |
题
考虑以下(脆弱的)JavaScript代码:
var img = new Image;
img.src = "data:image/png;base64,..."; // Assume valid data
// Danger(?) Attempting to use image immediately after setting src
console.log( img.width, img.height );
someCanvasContext.drawImage( img, 0, 0 );
// Danger(?) Setting onload after setting src
img.onload = function(){ console.log('I ran!'); };
问题
- 图像宽度和高度是否应该立即正确?
- 画布应该立即吸引工作吗?
- 应该
onload
调用(更改SRC之后设置)被调用?
实验测试
我创建了一个 简单的测试页面 具有类似的代码。在Safari我的第一个测试中,两者都在本地打开HTML页面(file:///
URL)并从我的服务器上加载它,显示了所有有效的工作:高度和宽度是正确的,画布绘制的作品, 和 这 onload
也开火。
在Firefox v3.6(OS X)中,启动浏览器后加载页面,表明设置后的高度/宽度不正确, drawImage()
失败。 (这 onload
但是,处理程序确实会发射。 drawImage()
在职的。似乎Firefox将数据URL的内容作为图像缓存,并在同一会话中使用时立即可用。
在Chrome V8(OS X)中,我看到了与Firefox中相同的结果:该图像不可立即可用,但是花费一些时间才能从数据URL中异步“负载”。
除了浏览上述内容或不起作用的实验证明外,我真的很喜欢与应该如何表现的规格链接。到目前为止,我的Google-Fu尚未完成这项任务。
安全地玩
对于那些不了解以上原因可能很危险的人,请知道您应该使用这样的图像安全:
// First create/find the image
var img = new Image;
// Then, set the onload handler
img.onload = function(){
// Use the for-sure-loaded img here
};
// THEN, set the src
img.src = '...';
解决方案
由于没有人发现有关这种情况的任何规格 应该 要表现出来,我们将不得不对它的方式感到满意 做 表现。以下是我的测试结果。
| is image data usable right | does onload callback set after src | after setting src? | is changed still get invoked? ------------+-----------------------------+------------------------------------- Safari 5 | yes | yes ------------+-----------------------------+------------------------------------- Chrome 8 | **no** (1st page load), but | yes FireFox 3.6 | yes thereafter (cached) | ------------+-----------------------------+------------------------------------- IE8 | yes (32kB data limit) | yes ------------+-----------------------------+------------------------------------- IE9b | yes | **no** ------------+-----------------------------+-------------------------------------
总之:
- 您不能假设图像数据将在设置Data-uri后立即可用;你必须等待
onload
事件。 - 由于IE9,您无法设置
onload
设置后处理程序src
并期望将其调用。 - 建议 “安全玩” (从上面的问题中)是确保正确行为的唯一方法。
如果有人可以找到讨论此问题的规格,我将很高兴地接受他们的答案。
其他提示
将控制权回到浏览器的渲染引擎后,测试报告 true
在FF 4B9和铬8.0.552.237中。我修改了这些部分:
img.onload = function(){ // put this above img.src = …
document.getElementById('onload').innerHTML = 'yes';
};
img.src = img_src;
…
window.setTimeout(function () { // put this inside setTimeout
document.getElementById('wh').innerHTML = (img.height==img.width) && (img.height==128);
}, 0);
更新: 是的,我理解这个“答案”更像是评论,但只是想指出。在测试后,我得到可重现的结果:
- 没有
setTimeout
, ,在两个浏览器中,我都会得到false
我第一次打开页面true
仅在击中 F5. 。明确清除缓存后都说false
重新加载后。 - 和
setTimeout
宽度/高度测试始终显示为true
.
在这两种情况下,仅在重新加载页面后,图像都不会首次显示。
不隶属于 StackOverflow