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

发布于 2024-10-13 15:17:41 字数 1463 浏览 6 评论 0原文

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

Consider the following (fragile) JavaScript code:

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 onload callback (set after the src was changed) be invoked?

Experimental Tests
I created a simple test page with 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, and the onload also fires.

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 onload handler 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.

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.

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

影子的影子 2024-10-20 15:17:41

由于还没有人找到关于其行为方式的任何规范,因此我们必须对其行为方式感到满意。以下是我的测试结果。

            | 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,您无法在设置 src 后设置 onload 处理程序并期望它被调用。
  • “谨慎行事”(来自上述问题)中的建议是确保正确行为的唯一方法。

如果有人能找到讨论此问题的规范,我会很乐意接受他们的答案。

As no one has yet found any specifications about how this is supposed to behave, we will have to be satisfied with how it does behave. 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 onload event.
  • Due to IE9, you cannot set the onload handler after setting the src and expect it to be invoked.
  • The recommendations in "Playing it Safe" (from the question above) are the only way to ensure correct behavior.

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

微凉徒眸意 2024-10-20 15:17:41

将控制权交还给浏览器渲染引擎后,测试在 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 ,只有在点击后才得到 true F5。显式清除缓存后,重新加载后都会再次显示 false
  • 使用 setTimeout 时,宽度/高度测试始终评估为 true

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

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

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 false the first time I open the page and true only after hitting F5. After explicitly clearing the cache both say false again after reloading.
  • with setTimeout the width/height test always evualuates to true.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文