是否应立即将图像src设置为数据URL?

时间:2011-01-23 21:33:47

标签: javascript html image data-uri

考虑以下(脆弱的)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更改后设置)?

实验测试
我创建了一个类似代码的simple test page。在Safari我的第一次测试,通过在本地打开HTML页面(file:/// url)并从我的服务器加载它,显示一切正常:高度和宽度是正确的,画布绘制工作, onload也会发射。

在Firefox v3.6(OS X)中,启动浏览器后加载页面会在设置后立即显示高度/宽度不正确,drawImage()失败。 (然而,onload处理程序会触发。但是,再次加载页面会在设置后立即显示宽度/高度正确,drawImage()正在工作。 Firefox似乎将数据URL的内容缓存为图像,并在同一会话中使用时立即可用。

在Chrome v8(OS X)中,我看到与Firefox相同的结果:图像无法立即使用,但需要一些时间从数据网址异步“加载”。

除了上述哪些浏览器有效或无效的实验证明之外,我真的很喜欢这些应该如何表现的规范的链接。到目前为止,我的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 = '...';

2 个答案:

答案 0 :(得分:52)

由于还没有人发现任何关于假设如何表现的规范,我们必须对 的行为方式感到满意。以下是我的测试结果。

            | 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**              
------------+-----------------------------+-------------------------------------

总结:

  • 您不能假设在设置数据后立即可以使用图像数据 - uri;您必须等待onload事件。
  • 由于IE9,您无法在设置onload后设置src处理程序,并期望调用它。
  • “安全播放”中的建议 (来自上述问题)是确保正确行为的唯一方法。

如果有人能找到讨论这个的规格,我会乐意接受他们的答案。

答案 1 :(得分:6)

将控制权交还给浏览器的渲染引擎后,测试报告FF 4b9和Chromium 8.0.552.237中的true。我修改了这些部分:

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,仅在点击 F5 后获得true。明确清除缓存后,重新加载后再次说false
  • setTimeout宽度/高度测试始终向true方向移动。

在这两种情况下,只有在重新加载页面后,图像才会第一次显示。