只测量特定页面元素加载完成的时间

3
我们使用修改过的Jiffy来测量实际客户端性能。
我们最重要的工作是测量请求接收到和页面加载事件在浏览器中触发之间的时间。
在某些页面上,我们有指向我们无法控制的外部站点的iframe元素,它们有时需要很长时间才能加载。目前,我们页面的页面加载事件仅在iframe完全加载后(并且它自己的加载事件触发)后触发。
我想分离这些测量 - 进行一次包括iframe在内的所有测量,但也进行一次没有iframe的测量 - 也就是说,如果我们没有iframe,页面加载将会发生。
到目前为止,我唯一成功的方法是在页面加载事件后将iframe添加到DOM中,但这会延迟iframe的加载。
有什么想法吗?

编辑:悬赏任务已结束,感谢大家的帮助和想法!我选择了Jed的答案,因为它给了我一个新的想法——开始加载iframes,但是“暂停”它们,以便它们不会影响页面加载(通过临时设置src="about:blank")。我将尝试添加更详细的结果摘要。

4个回答

3
您可以通过以下方式实现多个iframe的此操作,而无需动态添加它们:
  1. 在body加载之前将所有框架的src属性设置为about:blank,
  2. 让body加载事件触发,
  3. 添加一个onload处理程序来捕获每个框架的加载时间,然后
  4. 将每个框架的src属性恢复到其原始值。
我已创建了一个frameTimer模块,其中包含两种方法:
  1. 需要在 </body> 标签之前立即调用的init方法,以及
  2. 在页面加载时调用的测量方法,该方法带有包含结果的回调函数。
结果对象是这样的哈希:
{
    iframes: {
        'http://google.co.jp/': 1241159345061,
        'http://google.com/': 1241159345132,
        'http://google.co.uk/': 1241159345183,
        'http://google.co.kr/': 1241159345439
    },
    document: 1241159342970
}

该函数返回每次加载时间的整数,但很容易更改为仅返回文档正文加载的差异。

以下是它在实际操作中的工作示例,使用此JavaScript文件(frameTimer.js):

var frameTimer = ( function() {
    var iframes, iframeCount, iframeSrc, results = { iframes: {} };

    return {
        init: function() {
            iframes = document.getElementsByTagName("iframe"),
            iframeCount = iframes.length,
            iframeSrc = [];

            for ( var i = 0; i < iframeCount; i++ ) {
                iframeSrc[i] = iframes[i].src;
                iframes[i].src = "about:blank";
            }
        },

        measure: function( callback ) {
            results.document = +new Date;

            for ( var i = 0; i < iframeCount; i++ ) {
                iframes[i].onload = function() {
                    results.iframes[ this.src ] = +new Date;
                    if (!--iframeCount)
                        callback( results )
                };

                iframes[i].src = iframeSrc[ i ];
            }
        }
    };

})();

还有这个HTML文件(frameTimer.html):


<html>
    <head>
        <script type="text/javascript" src="frameTimer.js"></script>
    </head>
    <body onload="frameTimer.measure( function( x ){ alert( x.toSource() ) } )">
        <iframe src="http://google.com"></iframe>
        <iframe src="http://google.co.jp"></iframe>
        <iframe src="http://google.co.uk"></iframe>
        <iframe src="http://google.co.kr"></iframe>
        <script type="text/javascript">frameTimer.init()</script>
    </body>
</html>

使用jQuery可以用更少的代码(更不突兀地)完成此操作,但这是一种相当轻量级且无依赖性的尝试。


谢谢Jed,非常酷!我没有问题动态添加iframes。我不想延迟iframe内容的加载,仅在body的“load”事件上设置src可能会导致延迟。另一方面,在提前设置它然后在body标记结束前重置它实际上可以使浏览器开始下载框架组件,停止仅用于父类计时,然后继续。可能是一个好主意,我得测试一下看它是否可行。 - orip
1
没问题,Orip。您可以在此处查看结果:http://s3.amazonaws.com/frameTimer/index.html - Jed Schmidt
如果你想要在加载 iframe URLs 的第一次命中时测量其时间,那么你需要禁用浏览器缓存。否则,当你将 iframe URLs 替换为“about:blank”时,在 frameTimer.init() 代码段中,有些 iframe URLs 可能已经被缓存,而且由于缓存的原因 onload 时间可能会减少。 - Bharat Khatri

1

我对jiffy本身并不熟悉,但过去我使用了一个粗略的定制函数进行类似的测量,大致如下(从记忆中打字5分钟):

<html>
    <head>
        <script>
        var timer = {
            measure:    function(label)
                        {
                            this._timings[label] = new Date();
                        },
            diff:        function(a,b)
                        {
                            return (this._timings[b] - this._timings[a]);
                        },
            _timings: {}
        }
        </script>
    </head>
    <body onload="alert(timer.diff('iframe.start','iframe.done'));">
        <!-- lorem ipsum etc -->
        <script>timer.measure('iframe.start');</script>
        <iframe src="http://www.google.com" onload="timer.measure('iframe.done');"/>
        <!-- lorem ipsum etc -->
    </body>
</html>

从中可以看出,相关部分只需在遇到iframe之前立即记录日期戳,并添加一个事件处理程序到iframes的onload事件(无论iframe源的域是什么,都可以工作,而且不需要修改内容)以进行另一次测量(通常我会使用addEventListener/attachEvent添加这些事件,但你明白我的意思)。

这为您提供了一个时间跨度,您可以从总时间中减去它,以便在有和没有iframe的情况下给您一个合理的加载时间估计。

希望对您有所帮助


谢谢annakata。我认为page_load_time - iframe_load_time != page_load_time_without_iframe,因为其他元素与iframe及其元素并行加载,但也许我们无法做得更好:( - orip
那是我的感觉。唯一的防弹选项就是简单地测试带有和不带有 iframe 的版本,如果你想要一个粗略的解决方案,你必须选择类似上面的东西。我认为它们大部分时间不会太好,但这取决于你的测试平台。在任何接近实际使用情况的情况下,你很少会遇到瓶颈带宽、内存或处理器。 - annakata

0

我不确定这是否会对您有所帮助:

作为 jQuery 用户,我的代码在窗口的 onLoad 事件触发之前就已经执行完毕了。

让处理尽早进行是 jQuery 的一个基本功能(请参阅:jQuery Ready Event

然后,我可以向可能稍后完成加载的每个元素添加事件处理程序,包括 iframe。

但我理解,在您的情况下,这可能还不够,因为您想要获得"所有事情"的时间,而不加载 iframes。如果您在 jQuery ready 处理程序之外设置 iframe 源,我不确定 onLoad 窗口事件会发生什么。我猜它们将独立加载,但需要检查。

另一方面...此 ready 函数显示用户何时会看到页面正在"构建"。 图像和其他内容的加载大多是次要的。这就是为什么 Windows 在完成加载之前显示桌面的原因 :-)


好的观点-我检查了一下,在$(document).ready上设置iframe的源并没有帮助-页面的加载事件将延迟到iframe的加载事件。此外,这会导致iframe开始晚些加载。在页面加载后设置源(显然)不会延迟页面加载,但会更加延迟加载iframes。顺便说一句,我相信DOMReady事件-取决于页面-可能在页面开始渲染之后触发。例如,如果您在页面底部有一个缓慢的<script src="">。 - orip
好的。在jQuery中,dom-ready的使用意图是通过它来运行所有的脚本。所以它永远不会“延迟”执行(在理想的情况下)。我认为你无法获取页面加载时间,无论是否使用iframe。至少它永远不会100%准确。我认为使用domready可以使你的测量结果与慢速或快速的iframe加载保持平衡。这样你就能更好地了解自己应用程序/服务器的时序。 - OderWat
我尝试了其他方法来找出onload触发的时间。我在页面上添加了一个空的iframe和一些脚本,使用setTimeout()设置它的src。结果是,如果超时足够长以加载所有其他元素,则会触发onload。因此,它似乎像一个队列一样工作,每个新的加载“任何东西”都会增加事件的延迟...直到它触发一次。这可能是常识,但我从未问过。 - OderWat

0
我建议使用OderWat提出的“domready”事件,但有一个例外:您不需要jQuery来实现此事件。在http://dean.edwards.name/weblog/2006/06/again/上,对于所有三个(实际上是4个)主要浏览器都有很好的解释。
实际上,如果您在特定浏览器上运行测试,则更容易为跟踪实现此事件。
希望这可以帮助到您。

谢谢BYK,你是对的 - 你不需要jQuery来使用DOM准备好的时间。这可能更适合作为对OderWat答案的评论。 - orip
抱歉,下次会更加小心的;) 谢谢。 - BYK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接