【问题标题】:How to detect when an image has finished rendering in the browser (i.e. painted)?如何检测图像何时在浏览器中完成渲染(即绘制)?
【发布时间】:2013-01-12 18:07:03
【问题描述】:

在网络应用程序中,我需要处理大量高分辨率图像,这些图像会动态添加到 DOM 树中。它们是预先加载的,然后添加到页面中。

检测此类图像何时完成加载是一回事,为此我使用load 事件,但是如何使用Javascript 在浏览器中检测它何时完成呈现 ? 处理高分辨率图像时,实际的绘画过程可能会花费大量时间,知道何时结束非常重要。

【问题讨论】:

  • 图片的.load事件与实际渲染的结果是否真的有明显区别?
  • @Jack 恐怕非常如此。至少在非常大的分辨率图像上。
  • 我认为只有 Firefox 有 paint events 这可能是你可以使用的东西。
  • 哦,别告诉我这个! :( 我害怕这是我会听到的。没有跨浏览器的解决方案吗?
  • 图像的实际渲染很可能取决于开发人员无法控制的因素(在最终用户的计算机上)。 IE。 CPU 负载。所以最后,还是需要像“painted”这样的事件。

标签: javascript image dom-events


【解决方案1】:

我使用 requestAnimationFrame 来解决这个问题。加载图像后,它将在下一个动画帧期间渲染。因此,如果您等待两个动画帧,您的图像将被渲染。

function rendered() {
    //Render complete
    alert("image rendered");
}

function startRender() {
    //Rendering start
    requestAnimationFrame(rendered);
}

function loaded()  {
    requestAnimationFrame(startRender);
}

见http://jsfiddle.net/4fg3K/1/

【讨论】:

  • 它不适用于任何主流浏览器(在 Edge 15、Chrome 58 和 FireFox 53 上测试):在图像完成绘制之前会显示警告框。
  • 当我将代码放入图像 onload 回调时,这实际上对我有用。在最新的 Chrome 和 FF、IE 11、iOS 10.3.3 上的 Safari 中进行了测试,它在任何地方都可以使用(在屏幕上显示图像后出现警报)。我正在测试的图像也很大(大约 2 MB 桌面和 500 KB 移动)。
【解决方案2】:

我遇到了同样的问题。我已经创建了带有进度条的预加载器页面。图片加载完毕后,白底preloader页面平滑消失到opacity: 0,但图片依然没有渲染出来。

我终于使用了setInterval,当图像被加载(但未渲染)。在此期间,我检查了naturalWidth 和naturalHeight 属性(支持:IE9+)。最初它等于0,当图像被渲染时,它会显示其当前的宽度和高度。

const image = document.getElementById('image');

image.src = "https://cdn.photographylife.com/wp-content/uploads/2014/06/Nikon-D810-Image-Sample-1.jpg";

image.onload = function () {
  console.log('Loaded: ', Date.now());
  const interval = setInterval(() => {
    if (image.naturalWidth > 0 && image.naturalHeight > 0) {
      clearInterval(interval);
      rendered();
    }
  }, 20);
}

function rendered() {
  console.log('Rendered: ', Date.now());
}
img{
  width: 400px;
}
<img id="image"/>

【讨论】:

  • 使用naturalHeight和naturalWidth检测绘图根本不可靠。在我对 Firefox 52、Chromium 18 和 Chromium 91 的测试中,naturalWidth 和 naturalHeight 在图像的 onload 触发之前设置为 >0。两个 Chromium 版本都会在初始绘制图像之前提升 onload,而 Firefox 52 在初始绘制之后提升 onload。
【解决方案3】:

来自mdn,

MozAfterPaint 事件在重新绘制内容时触发 屏幕并提供有关已重新绘制的内容的信息。它是 主要用于研究性能优化

希望您这样做是为了衡量渲染图像的性能。

【讨论】:

    【解决方案4】:

    更新:不要使用这种方法 - 在图像尺寸设置为默认值以外的情况下不起作用

    您可以将元素的高度设置为自动(具有固定宽度)并通过超时继续检查元素的尺寸与图像的自然尺寸是否匹配。这不是最好的解决方案,但如果您真的需要在渲染后而不是在加载后做某事,这是一个不错的选择。

    或多或少是这样的:

    //this is NOT a real code
    function checkIfRendered(img, onRender) {
        var elRatio = img.width() / img.height();
        var natRatio = img.naturalWidth / img.naturalHeight;
    
        if (elRatio === natRatio)
            onRender();
        else {
            setTimeout(function() {
                checkIfRendered(imgEl, onRender)
            }, 20);
        }
    }
    
    img.onload(checkIfRendered(img, function() { alert('rendered!'); }));
    

    【讨论】:

    • 我相信浏览器会返回页面内保留图像空间的高度和宽度,而不是正在绘制的图像的大小。
    • 你是对的。如果图像上有一些设置其宽度或高度的 CSS,则此方法将无法正常工作。所以不要使用这个方法。我打算删除这个回复,但我会保留在这里,因为它可能会省去人们尝试类似事情的麻烦
    【解决方案5】:

    您需要<img> 标记上的onload 事件。例如:

    function loadImage () {
      alert("Image is loaded");
    }
    <img src="w3javascript.gif" onload="loadImage()" width="100" height="132">
    

    source

    如果图像是另一个元素的背景,则在背景中加载图像(使用简单的 Ajax GET 请求),当返回结果时,在加载后设置背景。

    【讨论】:

    • 这不是我想要的。正如 Jack 也指出的那样:渲染 (painting) != loading
    猜你喜欢
    • 2013-10-11
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多