开发者

Back button causes iFrame to delay window.onLoad event

I serve ads through an iFrame. The ad network's servers are much slower than mine, so I asyncronously load the iFrame on the window.onload event.

// (using Prototype library)
Event.observe(window, 'load', function() {
  $('ad').writeAttribute('src', '/ad.html');
  // other initialization here
});

A problem occurs when you enter the site via the browser's back button. Unexpectedly, the ad iFrame attempts to load immediately (before the load listener above sets the 'src' attribute), delaying the load event for a few seconds. During these few seconds, the site is unusab开发者_开发问答le because I do a bunch of initialization in window.onload.

As far as I know, this only happens in Firefox. How do I prevent this blocking load?


The problem is probably Firefox's bfcache (back/forward cache), which keeps pages loaded for quicker navigation using the back and forward buttons. You can disable it for your page by binding an unload handler.


Theory

The issue you've noticed could be described like this: an iframe in a document loads the URL loaded in it at the moment the outer page was navigated from, not the URL specified in the outer page's HTML source (or an empty page in your case).

The fact that it delays onload is just a corollary: the load event is delayed until all the resources (images, frames, etc) are finished loading.

I couldn't find documentation explaining that it should happen this way, nor any bug reports acknowledging it as a known issue, but FWIW I see exactly the same behavior with Google Chrome 10.0.612.3 on the testcase below.

This behavior, even though unintuitive in your case, has some logic behind it: document loads in frames historically are recorded in the session history (back/forward navigation history). Suppose you open a site, that has its main content in a frame, and navigate the inner iframe. After going away from the site, then returning via the back button, the browser should arguably load the last loaded page in the frame.

Solutions

Surprisingly, this doesn't appear to be a common question, so these suggestions are based on my understanding of the issue, I haven't tested them in any scenario more real than the testcase below.

  1. The best experience for the user would be if you made the bfcache work. As far as I can see, this would require the ad document be cacheable (using different URLs to show different ads, instead) and possibly changes to the JS framework you use (if it happens to always break bfcache, I don't know, this used to be a problem with other frameworks).
    If you pulled this off though, there would be no load event at all, the page would just be restored exactly in the state it was left in, and it would much snappier than anything that hits the network.
  2. The only way to prevent the iframe from loading the URL from session history I can think of is to avoid having the iframe in the HTML source. If you insert it dynamically, it wouldn't be the "same" iframe the next time the page loads, so it would default to the URL you specify in its src.
  3. Instead of trying to prevent the iframe from loading the ad on 'back', you could make your code currently running off the load event not be blocked by the iframe. For this you could use the DOMContentLoaded event.

Appendix: Testcase

<iframe id="a"></iframe>
<pre id="b"></pre>
<script>
var b = document.getElementById("b")
b.innerHTML += "before 'load': iframe src=" + document.getElementById("a").src + "\n";
window.addEventListener("load", function() {
  var newURL = "https://developer.mozilla.org/en/HTML/Element/iframe";
  b.innerHTML += "onload: iframe src=" + document.getElementById("a").src + "\n";
  b.innerHTML += "setting src to " + newURL + "\n";
  document.getElementById("a").src = newURL;
  b.innerHTML += "now iframe src=" + document.getElementById("a").src + "\n";
}, false);

// disable bfcache
window.onunload = function() {}
</script>


Worth trying is to delay the writeAttribute until the rest of the Event is processed:

Event.observe(
 window,
 'load',
 function() {
  setTimeout(function() { 
    $('ad').writeAttribute('ad.html');
  }, 0);
 }
);

This will execute as soon as everything else is done.


Worth trying is to delay the writeAttribute until the rest of the Event is processed:

Event.observe(
 window,
 'load',
 function() {
  setTimeout(function() { 
    $('ad').writeAttribute('ad.html');
  }, 0);
 }
);

This will execute as soon as everything else is done.

Huh, SO won't let me put in two answers

I don't know why this is happening but you try putting another iframe between your page and the ad: your page loads an iframe; that iframe waits a few seconds (letting your page load), then loads the ad, which will take up the entire area of the intermediate iframe.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜