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

IT技术 javascript html image data-uri
2021-01-22 03:48:02

考虑以下(脆弱的)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 = '...';
2个回答

由于没有一个目前尚未发现这是怎么任何规格应该的行为,我们将不得不与它是如何满足循规蹈矩。以下是我的测试结果。

            | 图像数据是否可用?在 src 之后设置 onload 回调
            | 设置src后?| 改变了仍然被调用?
------------+--------------------------------------------+------- ------------------------------
Safari 5 | 是 | 是的                
------------+--------------------------------------------+------- ------------------------------
铬 8 | **不**(加载第一页),但是 | 是的                
火狐 3.6 | 之后是(缓存)|                                     
------------+--------------------------------------------+------- ------------------------------
IE8 | 是(32kB 数据限制)| 是的         
------------+--------------------------------------------+------- ------------------------------
IE9b | 是 | **不**              
------------+--------------------------------------------+------- ------------------------------

总之:

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

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

@Phrogz 您在哪个阶段或文档状态进行了该测试?我正在观察 Safari 5.1 是否具有 Chrome 行为,但那是在window.load事件发生之前你的测试是在加载之后还是之前进行的?你是否记得?
2021-03-12 03:48:02
感谢您在这里所做的研究。我一直在努力解决在需要使用画布报告的离线 Web 应用程序中强制执行此行为的可能性,因此我进行了更多挖掘。现行的 WHATWG 规范实际上确实将缓存的情况称为同步,将非缓存的情况称为异步。查核在规范的src节第7步在这里找到:whatwg.org/specs/web-apps/current-work/multipage/...如果图像在文档的“可用图像列表”中,它会同步完成,或者这就是我阅读它的方式。
2021-04-03 03:48:02

在将控制权交还给浏览器的渲染引擎后,trueFF 4b9 和 Chromium 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宽度/高度测试总是evualuates到true

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

您是在告诉我,如果没有这些更改,您会在 FF 和 Chromium 中看到“失败”吗?我的问题不是如何使这项工作 -onload在之前明确设置src并且仅在回调中引用图像才有效。我的问题是是否存在描述这应该如何工作的规范。
2021-03-26 03:48:02