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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4776670/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 14:02:36  来源:igfitidea点击:

Should setting an image src to data URL be available immediately?

javascripthtmlimagedata-uri

提问by Phrogz

Consider the following (fragile) JavaScript code:

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

The Question(s)

问题

  • Should the image width and height be correct immediately?
  • Should the canvas draw work immediately?
  • Should the onloadcallback (set after the src was changed) be invoked?
  • 图像宽度和高度是否应该立即正确?
  • 画布绘图应该立即工作吗?
  • 是否应该onload调用回调(在 src 更改后设置)?

Experimental Tests
I created a simple test pagewith similar code. In Safari my first tests, both by opening the HTML page locally (file:///url) and loading it from my server, showed everything working: the height and width is correct, the canvas draw works, andthe onloadalso fires.

实验测试
我用类似的代码创建了一个简单的测试页面。在Safari我的第一次测试,都是由本地打开HTML网页(file:///URL),并从我的服务器加载它,结果显示一切工作:高度和宽度是正确的,在画布上绘制的作品,并且onload还火。

In Firefox v3.6 (OS X), loading the page after launching the browser shows that the height/width is not correct immediately after setting, drawImage()fails. (The onloadhandler does fire, however.) Loading the page again, however, shows the width/height being correct immediately after setting, and drawImage()working. It would appear that Firefox caches the contents of the data URL as an image and has it available immediately when used in the same session.

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

In Chrome v8 (OS X) I see the same results as in Firefox: the image is not available immediately, but takes some time to asynchronously 'load' from the data URL.

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

In addition to experimental proof of what browsers the above does or does not work, I'd really love links to specs on how this is supposed to behave. So far my Google-fu has not been up to the task.

除了上述浏览器工作或不工作的实验证明之外,我真的很喜欢链接到关于它应该如何表现的规范。到目前为止,我的 Google-fu 还没有完成这项任务。

Playing It Safe
For those who don't understand why the above might be dangerous, know that you should use images like this to be safe:

安全操作
对于那些不明白为什么上述内容可能很危险的人,请知道您应该使用这样的图像来确保安全:

// 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 = '...';

采纳答案by Phrogz

As no one has yet found any specifications about how this is supposedto behave, we will have to be satisfied with how it doesbehave. Following are the results of my tests.

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

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

In summary:

总之:

  • You cannot assume that the image data will be available right after setting a data-uri; you must wait for the onloadevent.
  • Due to IE9, you cannot set the onloadhandler after setting the srcand expect it to be invoked.
  • The recommendations in "Playing it Safe"(from the question above) are the only way to ensure correct behavior.
  • 您不能假设在设置 data-uri 后图像数据将立即可用;你必须等待onload事件。
  • 由于 IE9,您不能onload在设置后设置处理程序src并期望它被调用。
  • 在这些建议“谨慎行事”(从上面的问题)是确保正确的行为的唯一途径。

If anyone can find specs discussing this, I will happily accept their answer instead.

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

回答by Marcel Korpel

After giving control back to the browser's rendering engine, the test reports truein FF 4b9 and Chromium 8.0.552.237. I modified these parts:

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

Update:Yes, I understand this 'answer' is more like a comment, but just wanted to point it out. And after testing I get reproducible results:

更新:是的,我知道这个“答案”更像是评论,但只是想指出它。经过测试,我得到了可重复的结果:

  • without setTimeout, in both browsers I get falsethe first time I open the page and trueonly after hitting F5. After explicitly clearing the cache both say falseagain after reloading.
  • with setTimeoutthe width/height test always evualuates to true.
  • 没有setTimeout,在两种浏览器中,我false都是第一次打开页面,并且true只有在点击F5. 明确清除缓存false后,重新加载后都再说一遍。
  • setTimeout宽度/高度测试总是evualuates到true

In both cases the image doesn't show up the first time, only after reloading the page.

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