26

对于反应时间研究(如果您有兴趣,请参阅此问题),我们想要控制和测量图像的显示时间。我们想考虑在不同用户的机器上重新绘制所需的时间。

编辑:最初,我只使用内联执行来计时,并且认为我不能相信它能够准确地测量图片在用户屏幕上可见的时间,因为绘画需要一些时间。

后来,我找到了事件“ MozAfterPaint ”。它需要更改配置才能在用户的计算机上运行,​​而相应的WebkitAfterPaint没有成功。这意味着我不能在用户的计算机上使用它,但我将它用于我自己的测试。我在下面粘贴了相关的代码片段和我的测试结果。
我还使用 Chrome 中的SpeedTracer手动检查了结果。

// from the loop pre-rendering images for faster display
var imgdiv = $('<div class="trial_images" id="trial_images_'+i+'" style="display:none"><img class="top" src="' + toppath + '"><br><img class="bottom" src="'+ botpath + '"></div>');
Session.imgs[i] = imgdiv.append(botimg);
$('#trial').append(Session.imgs);

// in Trial.showImages
$(window).one('MozAfterPaint', function () {
    Trial.FixationHidden = performance.now();
});
$('#trial_images_'+Trial.current).show(); // this would cause reflows, but I've since changed it to use the visibility property and absolutely positioned images, to minimise reflows
Trial.ImagesShown = performance.now();

Session.waitForNextStep = setTimeout(Trial.showProbe, 500); // 500ms    

// in Trial.showProbe
$(window).one('MozAfterPaint', function () {
    Trial.ImagesHidden = performance.now();
});
$('#trial_images_'+Trial.current).hide();
Trial.ProbeShown = performance.now();
// show Probe etc...

比较使用 MozAfterPaint 和内联执行测量的持续时间的结果。

这不会让我太高兴。首先,中值显示持续时间比我想要的短约 30 毫秒。其次,使用 MozAfterPaint 的方差非常大(并且比内联执行更大),所以我不能简单地通过将 setTimeout 增加 30 毫秒来调整它。第三,这是在我相当快的计算机上,其他计算机的结果可能会更糟。

持续时间箱线图

使用两种方法测量的持续时间的关系

SpeedTracer 的结果

这些更好。图像可见的时间通常在预期持续时间的 4(有时)10 毫秒内。看起来 Chrome 也考虑了在调用中重新绘制所需的时间setTimeout(因此,如果图像需要重新绘制,则调用之间存在 504 毫秒的差异)。不幸的是,我无法在 SpeedTracer 中分析和绘制许多试验的结果,因为它只记录到控制台。我不确定 SpeedTracer 和 MozAfterPaint 之间的差异是否反映了两个浏览器的差异,或者是我在使用 MozAfterPaint 时缺少的东西(我很确定我正确地解释了 SpeedTracer 输出)。

问题

我想知道

  1. 如何测量它在用户机器上实际可见的时间,或者至少获得不同测试计算机(Chrome、Firefox、Safari)上一组不同浏览器的可比数字?
  2. 我可以抵消渲染和绘画时间以达到 500 毫秒的实际可见性吗?如果我必须依赖通用偏移,那会更糟,但仍然比在如此短的时间内显示图像要好,以至于用户在速度较慢的计算机上不会有意识地看到它们。
  3. 我们使用setTimeout. 我知道,requestAnimationFrame但似乎我们无法从使用它中获得任何好处:
    该研究应该是整个研究期间的焦点,更重要的是我们获得 +/-500 毫秒的显示而不是某个特定的帧数。我的理解正确吗?

显然,Javascript 对此并不理想,但它对我们的目的来说是最不坏的(该研究必须在用户自己的计算机上在线运行,要求他们安装一些东西会吓跑一些人,Java 没有捆绑在 Mac OS X 浏览器中不再)。
目前我们只允许当前版本的 Safari、Chrome、Firefox 和 MSIE(性能检测功能。现在和全屏 API,我还没有检查 MSIE 是如何做的)。

4

2 回答 2

5

因为我还没有得到更多答案,但在编辑这个问题时学到了很多东西,所以我将我的进展发布为答案。如您所见,它仍然不是最佳的,我很乐意将赏金奖励给任何改进它的人。

统计数据

新结果

  • 在最左边的面板中,您可以看到导致我怀疑我得到的时间估计的分布。
  • 中间面板显示了我在缓存选择器、重新排序一些调用、使用更多链接、使用visibility绝对定位而不是display.
  • 最右边的面板显示了我在使用由Joe Lambert使用 requestAnimationFrame 改编的函数后得到的结果。在阅读了一篇关于 rAF 现在也具有亚毫秒精度的博文后,我做到了这一点。我认为它只会帮助我平滑动画,但显然它也有助于获得更好的实际显示持续时间。

结果

在最后一个面板中,“paint-to-paint”时间的平均值约为 500 毫秒,内联执行时间的平均值实际上是分散的(有道理,因为我使用相同的时间戳来终止下面的内部循环)并与“paint -to-paint”的时机。

持续时间仍然存在很大差异,我很想进一步减少它,但这绝对是进步。我将不得不在一些速度较慢的 Windows 计算机上对其进行测试,看看我是否真的对它感到满意,最初我希望所有偏差都低于 10 毫秒。

如果我制作了一个不需要用户交互的测试套件,我也可以收集更多的数据,但我想在我们的实际应用程序中这样做以获得现实的估计。

window.requestTimeout使用 window.requestAnimationFrame

window.requestTimeout = function(fn, delay) {
    var start = performance.now(),
        handle = new Object();
    function loop(){
        var current = performance.now(),
            delta = current - start;

        delta >= delay ? fn.call() : handle.value = window.requestAnimationFrame(loop);
    };
    handle.value = window.requestAnimationFrame(loop);
    return handle;
};

编辑:

我的另一个问题的答案链接到一篇不错的新文章

于 2013-01-24T18:21:04.370 回答
4

您是否尝试获取初始毫秒,并在事件触发后计算差异?而不是 setTimeout。就像是:

var startDate = new Date();
var startMilliseconds = startDate.getTime();

// when the event is fired :
(...), function() {
    console.log(new Date().getTime() - startMilliseconds);
});

如果可能,尽量避免使用 jQuery。纯 JS 将为您提供更好的响应时间和更好的整体性能

于 2013-01-20T14:02:38.667 回答