考虑以下(脆弱的)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.

在这两种情况下,仅在重新加载页面后,图像都不会首次显示。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top