应该立即设置一个图像src到数据URL?

考虑下面的(脆弱的)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!'); }; 

问题(S)

  • 图像宽度和高度是否应该立即正确?
  • canvas是否应立即绘制?
  • 应该onloadcallback(在src之后设置)吗?

实验testing
我用类似的代码创build了一个简单的testing页面 。 在Safari中,我的第一个testing是通过在本地打开HTML页面( file:/// url)并从我的服务器加载它,显示了所有的工作:高度和宽度是正确的,canvas绘制工作, onload也触发。

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

在Chrome v8(OS X)中,我看到了与Firefox中相同的结果:图像不是立即可用,但需要一些时间从数据URLasynchronous“加载”。

除了上面的浏览器做了什么或不工作的实validation明之外,我真的很喜欢关于这个应该如何performance的规范的链接。 到目前为止,我的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 = '...'; 

由于还没有人find有关这种行为的规范,我们必须对它的行为表示满意。 以下是我的testing结果。

             | 是可以使用的图像数据 在src之后的onloadcallback设置
             | 设置src后?  | 改变仍然被调用?
 ------------ + ----------------------------- + ------- ------------------------------
 Safari 5 | 是| 是                
 ------------ + ----------------------------- + ------- ------------------------------
 Chrome 8 |  **没有**(第一页加载),但| 是                
 FireFox 3.6 | 之后是(caching)|                                     
 ------------ + ----------------------------- + ------- ------------------------------
 IE8 | 是(32kB数据限制)| 是         
 ------------ + ----------------------------- + ------- ------------------------------
 IE9b | 是|  **没有**              
 ------------ + ----------------------------- + ------- ------------------------------

综上所述:

  • 设置data-uri后,您不能假定图像数据可用。 你必须等待onload事件。
  • 由于IE9,你不能在设置src之后设置onload处理程序,并期望它被调用。
  • “保证安全”的build议(从上面的问题)是确保正确行为的唯一途径。

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

将控制权交给浏览器的渲染引擎后,testing结果在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); 

更新:是的,我明白这个“答案”更像是一个评论,但只是想指出来。 经过testing,我得到了可重现的结果:

  • 没有setTimeout ,在两个浏览器中,我第一次打开页面时为true仅在打开F5后才为false 。 明确清除caching后,重新加载后都会再次声明为false
  • setTimeout的宽度/高度testing总是performance为true

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