How to load IFRAMEs in order according to priority

Let’s say you have a Web page that displays “widgets” a small islands of information. And internally those widgets are IFRAME elements, whose source is loaded dynamically from the same server at runtime in client side JavaScript. So, you have a code similar to this:

var aIframes = document.getElementsByTagName('IFRAME');
for (var I = 0; I < aIframes.length; I++) {
    aIframes[I].src = aIframes[I].getAttribute('originalURL')
}

This (oversimplified) code assumes that URL for IFRAME source already stored as a custom attribute ‘originalURL’ of IFRAME element (for example placed there by server-side code), but it can equally come from other sources. This approach is usually taken so IFRAMES can initially display a static page with “Please wait. Loading…” animation meanwhile dynamically loading real data – creates a better user experience.

The code loops thru all IFRAMEs setting their SRC attribute, displaying content, so you would see something like

IFRAME widgets

It’s all well and good, but there’s a small problem. SRC of IFRAMEs is assigned in order of their appearance on the page and if URLs are pointing to the same server and one of the earlier IFRAMEs takes a long time to load – it will block the rest of the IFRAMEs from loading.

This is happening because browser can only have a limited number of open connections to the server, it’s especially apparent in Internet Explorer which only has 2. But even the rest of them can quickly run out of open connections keeping the user waiting – which is especially frustrating if you know that some of those IFRAMEs only take fraction of a second to load – still they will have to wait till early ones finish loading.

The solution is not to assign URL right away but add all the IFRAME elements to an array, sort that array and assign URL to IFRAMEs while looping thru sorted array. Allow me to elaborate.

Let’s assume that every IFRAME element has another custom attribute called ‘priority’, which, again, can be assigned by many means – including server-side code. ‘priority’ attribute is a number (1,2,3…) indicating IFRAME load priority (the lower the number the higher the priority). Let’s modify the code above a little:

var aIframes = document.getElementsByTagName('IFRAME');
var aIframeArray = [];

for (var I = 0; I &lt; aIframes.length; I++) {
    aIframeArray.push(aIframes[I])
}

aIframeArray.sort(function (a, b)
                   { return a.getAttribute('priority') - b.getAttribute('priority') })

for (var I = 0; I < aIframeArray.length; I++) {
    aIframeArray[I].src = aIframeArray[I].getAttribute('originalURL')
}
  • Line 02 creates a new array to hold IFRAME elements.
  • Lines 04-06 loop thru IFRAME elements, adding them to that array.
  • Lines 08-09 sort that array. Note how you can sort array of objects by object property by passing a custom comparasion function (Thanks Larry Gomez for this neat trick!).
  • Lines 11-13 loop thru sorted-by-priority array, giving SRC proprty of IFRAME elements their URL.

Final result: IFRAMEs with higher priority (lower ‘priority’ attribute number) get their SRC set first thus loading faster leaving slower IFRAMES to load last.


UPDATE 5/9/2013 – thanks Peter for the setInterval idea
After extensive use of the above solution I realized that the last loop thru sorted-by-priority array not always yields expected result, even though array is already sorted. We need to give IFRAME time to load and for this setInterval is a perfect match:

var I = 0;
var bPrevIframeLoaded = true;
var iInterval = setInterval(function () {
   if (I < aIframeArray.length) {
      if (bPrevIframeLoaded) {
         bPrevIframeLoaded = false;
         aIframeArray[I].onload = function () { bPrevIframeLoaded = true};
         aIframeArray[I].src = aIframeArray[I].getAttribute('originalURL');
         I++
      }
   } else {
      clearInterval(iInterval)
   }
}, 100)

Replace Lines 11-13 of the previous code block with this code. It’s a bit more involved, but this time 100% guaranteed that priority will be obeyed. Here’s how the magic happens:
Lines 13, 24 kick off timer that is called every 100ms. On every call function checks whether we reached end of array (Line 14) and if not – proceed further. Then it checks whether previous IFRAME finished loading (Line 15) and if it has – proceed further. Then it sets current IFRAME “already loaded” flag to FALSE (Line 16) and making sure when IFRAME does finish loading – the flag is set back to TRUE (Line 17). Then it sets IFRAME source and advances to next element in the array (Lines 18-19). If we reached the end of array – we stop timer and exit (Lines 21-23). That’s all folks.


UPDATE-2 5/10/2013 – A little cross-browser love
Turned it that wasn’t exactly all. Using “iframe.onload = function” doesn’t work in all browsers (IE8, I am looking at you). So to make it truly universal, replace Line 17 in the above code with

if (aIframeArray[I].addEventListener)
  aIframeArray[I].addEventListener('load', function () { bPrevIframeLoaded = true }, false)
else
  aIframeArray[I].attachEvent('onload', function () { bPrevIframeLoaded = true })

or, if you use MS AJAX extention with oneliner:

$addHandler(aIframeArray[I], 'load', function () { bPrevIframeLoaded = true })

or any other framework’s universal “add event” method.

2 replies on “How to load IFRAMEs in order according to priority”

  1. where is this code paced within the document? What would it look like with 4 iframes? Thanks.

  2. @Confused – the code can be placed in “onload” event of the page, and number of iframes doesn’t really matter – the code is universal and accounts for all iframes in the document.

Leave a Reply

Your email address will not be published. Required fields are marked *