views:

620

answers:

4

We use a modified version of Jiffy to measure actual client-side performance.

The most important thing we do is measure the time between when the request was received and when the page load event fires in the browser.

On some pages we have iframe elements that point to external sites that we don't control - they sometimes take a long while to load. At the moment, the page load event for our page fires only after the iframe is completely loaded (and it's own load event fires).

I'd like to separate these measurements - have one measurement after everything including the iframe is loaded, but also one measurement without the iframe - that is, when the page load would have occured if we didn't have an iframe.

The only way I've managed to do this so far is to add the iframe to the DOM after the page load event, but that delays the loading of the iframe.

Any ideas? Thanks!

EDIT: bounty is over, thanks for the help and ideas! I chose Jed's answer because it gave me a new idea - start loading the iframes, but "pause" them so they won't affect page load (by temporarily setting src="about:blank"). I'll try to add a more detailed summary of my results.

+1  A: 

I'm not familiar with jiffy per se, but in the past I've done similar measurements using a crude bespoke function, roughly like this (5 mins typing from memory):

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

From that you can see the relevant part is simply to note a datestamp immediately before the iframe is encountered, and then add an event handler to the iframes' onload event (which will work regardless of the domain of the iframe source and doesn't require modifying the content) to take another measurement (normally I'd add these events with addEventListener/attachEvent but you get the idea).

That gives you a timespan for the iframe you can subtract from the total to give you a reasonable idea of loadtime with and without iframe.

HTH

annakata
Thanks annakata. I think that page_load_time - iframe_load_time != page_load_time_without_iframe, because other elements are being loaded in parallel with the iframe and its elements, but maybe we can't do anything better :(
orip
That was my feeling. The only bulletproof option is to simply test a version with and without the iframe, if you want a rough and ready you have to go with something similar to the above. I don't think they != will be too great most of the time but it depends on your testing platform. On anything approaching a realistic use-case you're very unlikely to bottleneck bandwidth, memory or proc.
annakata
+2  A: 

You can achieve this for multiple iframes without dynamically adding them by:

  1. setting the src attribute for all frames to about:blank before body load,
  2. letting the body load event fire,
  3. adding an onload handler to capture the load time of each frame, and then
  4. restoring the src attribute of each frame to its original value.

I've created a frameTimer module that consists of two methods:

  1. an init method that needs to be called immediately before the </body> tag, and
  2. a measure method to be called on page load, which takes a callback with the results.

The results object is a hash like this:

{
    iframes: {
        'http://google.co.jp/': 1241159345061,
        'http://google.com/': 1241159345132,
        'http://google.co.uk/': 1241159345183,
        'http://google.co.kr/': 1241159345439
    },
    document: 1241159342970
}

It returns integers for each load time, but could be easily changed to just return the diff from the document body load.

Here's a working example of it in action, with this javascript file (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 ];
   }
  }
 };

})();

and this html file (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"&gt;&lt;/iframe&gt;
  <iframe src="http://google.co.jp"&gt;&lt;/iframe&gt;
  <iframe src="http://google.co.uk"&gt;&lt;/iframe&gt;
  <iframe src="http://google.co.kr"&gt;&lt;/iframe&gt;
  <script type="text/javascript">frameTimer.init()</script>
 </body>
</html>

This could be done in a lot less code (and less obtrusively) with jQuery, but this is a pretty lightweight and dependency-free attempt.

Jed Schmidt
Thanks Jed, pretty cool! I don't have a problem adding the iframes dynamically. I don't want to delay the loading of the iframe contents, and setting the src only on the body's "load" event could cause that. On the other hand, setting it in advance then resetting it before the end of the body tag could actually make the browser start downloading the frames components, stop just for the parent's timing, and then continue. Could be a great idea, I'll have to test to see if it works.
orip
No problem orip. You can see the results working here: http://s3.amazonaws.com/frameTimer/index.html
Jed Schmidt
A: 

I am not sure if it will help you:

As jQuery user I get my code executed long before the onLoad event of the window fires.

It is an essential functionality of jQuery to allow processing as soon as the DOM of the loaded page is ready (see: jQuery Ready Event)

I then can add event handlers to every element which may finish loading "later" including the iframes.

But I understand that this may not be enough for your case as you want to have the timing of "everything" as without loading of the iframes. I am not sure what happens to the onLoad event of the window if you set the iframe sources out of the jQuery ready handler. I guess they will load independently but that needs to be checked.

On the other side... this ready function shows when people will see your page "building up". Loading of images and stuff is mostly secondary for perception of humans. That is why windows shows the desktop before it is finished loading for a while now :-)

OderWat
Good points - I checked this and setting the iframe's sources on $(document).ready doesn't help - the page's load event will be delayed until the iframe's load event. Also, this causes the iframes to start loading later. Setting the sources after page load will (obviously) not delay the page load, but delays loading the iframes even more. BTW, I believe the DOMReady event - depending on the page - can fire after the page has started rendering. For example, if you have a slow <script src=""> at the bottom of your page.
orip
Ok. The idea of the dom-ready usage in jQuery is to run all your scripts through it. So it would never be able to fire "late" (in a perfect world).I believe you can't not get the loading time of the page with and without the iframe. At least it will never be 100% correct.I thought that using the domready will even out your measurements with slow or fast iframe loading. So you have a better picture of your own application/server timing.
OderWat
I tried something else to find out when onload triggers. I added an empty iframe to a page and some script which sets it src with setTimeout(). The result was, that it triggers the onload if the timeout is long enough to load all the other elements. So it seems to work like a queue where every new loading "anything" will add to the delay of the event... until it triggers once. That may be common knowledge but I did never asked about it.
OderWat
A: 

I'll suggest the "domready" event as OderWat suggested with one exception: you do not need jQuery to implement this event. At http://dean.edwards.name/weblog/2006/06/again/ it is well explained for All three(actually 4) major browsers.

Actually, if you run your tests on a specific browser, it is easier for you to implement this event for tracking.

Hope it helps.

BYK
Thanks BYK, you're right - you don't need jQuery to use the DOM ready timing. This would probably have been more appropriate as a comment to OderWat's answer.
orip
Sorry about that, will be more careful next time ;) Thank you.
BYK