title: Script in Internet Explorer (IE) hangs and becomes unresponsible with empty cache (works fine with cache)
body: <p>Ok, I have put together a script which does this:</p>
  
  <ol>
  <li>Make ajax request (via getHTTPObject(), no libraries is used)</li>
  <li>Create an iframe with script, src is "blank.html".</li>
  <li>use iframe.document.write() to execute scripts (inkluding document.write based scripts) in the iframe.</li>
  <li>call parent window's document to clone the iframe content.</li>
  <li>Append the content clone to parent body.</li>
  </ol>
  
  <p>Works like a charm in all browsers but IE, where every version - including IE9 beta - hangs on iframeWindow.document.close() with empty cache, leaving the window/tab unresponsible. When I force quit, restart and load the page again it works.</p>
  
  <p>What I've tried already:</p>
  
  <ul>
  <li>Googled.</li>
  <li>called the ajax request callback manually with string instead of request.responseText - it works even with empty cache here.</li>
  <li>Removed document.close() - resulting in scripts in iframe not executing at all (again, only with empty cache, cached pages works fine).</li>
  <li>Tested to make the ajax request synchronous - no difference.</li>
  </ul>
  
  <p>Any ideas?</p>
  
  <p>Live example here:
  <a href="http://labs.adeprimo.se/~adupanyt/ot/unlimited_scroll/" rel="nofollow">http://labs.adeprimo.se/~adupanyt/ot/unlimited_scroll/</a></p>
  
  <p>Here is the code. The install(), finish() and append()-functions manages the iframe.</p>
  
  <pre><code>/*!
   * Cross browser unlimited scroll snippet
   * Copyright (c) 2010 by Adeprimo.
   * Released under the MIT license. 
   */
  /* Code assumptions:
   *
   *      &lt;div id="unlimited-scroll-wrapper"&gt;
   *
   *          ... first content ...
   *
   *          &lt;a id="load-more-unlimited-content" href="/nyheter"&gt;
   *            Ladda mer innehåll&lt;/a&gt;
   *      &lt;/div&gt;
   */
  (function(window, document, undefined){
      /**
       * This snippet has two running modes, and it is the load_on_scroll
       * directive which rules it.
       * 
       * true     = a scroll event is initiated, which will wait 
       *            until the bottom is reached before it load any new content.
       * false    = this script will continue loading more content, one piece 
       *            at the time, until there is no more to get.
       *
       */
      load_on_scroll = false;
  
      var request;    // results of getHTTPObject()
      var wrapper;    // reference to the element which stores the new contents.
      var callsCount; // keep the count of ajax calls, helps css targeting.
      var attachEvent;// stores result of window.attachEvent for performance
  
      // locks, these are updated by the script.
      window.mkt_nothing_more_to_load = false;// true when end of queue reached. 
      window.mkt_prevent_new_loading = false; // true when ajax in progress.    
  
      wrapper = document.getElementById('unlimited-scroll-wrapper');
      callsCount = 1;
      attachEvent = window.attachEvent;
  
      /**
       * Customize this function for your need.
       * It is called each time a new document fragment
       * shall load. 
       * In here, you might add some nifty jQuery or Prototype if your app
       * has it.
       */
      function load_and_append() {
          var src; // href attribute of the #load-more-unlimited-content A element
  
          // get the source
          src = document.getElementById('load-more-unlimited-content').href;
  
          // mktwebb specific, will only return the content and 
          // not the header or footer. 
          src = src.replace(/\?.+?$/, '') + '?segment=content,footer';
  
          if (!request) { 
              request = getHTTPObject();  // getHTTPObject must be declared 
          }                               // separately!
  
          if (request) {
              request.onreadystatechange = function() {
                  if (request.readyState == 4) {
                      if (request.status == 200 || request.status == 304) {
                          console.log('append() begin');
                          append(request.responseText, src);
                          console.log('append() done');
                      }
                  }
              };
  
              request.open("GET", src, false);
              request.send(null);
          }
      }
  
      function finish(iframe_window) {
          var acc_elm = (function(doc){
              return doc.getElementsByTagName('div')[0].cloneNode(true);
          })(iframe_window.document);
  
          document.getElementById('unlimited-scroll-wrapper').appendChild(acc_elm);
  
          window.mkt_prevent_new_loading = false; // we are ready to more content.
  
          // we are done with the iframe, let's remove it.
          var iframe_container = document.getElementById('mkt_iframe-container');
          iframe_container.parentNode.removeChild(iframe_container);
  
          // basically, the script continues as long as it finds a new 
          // #load-more-unlimited-content element in the newly added content. 
          // if it can't find the #load-more-unlimited-content,
          // the script will stop and unattach itself.
          if (document.getElementById('load-more-unlimited-content')) {
              // if load_on_scroll, the new content is added under 
              // the control of the scroll event. There is no need to call
              // load_and_append here since the scroll event will manage
              // that fine.
              // however, when not load_on_scroll,
              // new content should be loaded asap.
              if (!load_on_scroll) {
                  window.mkt_prevent_new_loading = true;
                  // give the browser some time to reflow and rest, then continue.
                  setTimeout(load_and_append, 2 * 1000);
              }
          } else {
              nothing_more_to_load = true; // tell the scroll event to stop.
  
              // remove scroll event since it is not needed anymore 
              if (attachEvent) {
                  window.detachEvent('onscroll', 
                      look_for_trouble); // ie
              } else {
                  window.removeEventListener('scroll', 
                      look_for_trouble, false); // w3c
              }
          }
      };
      window['mkt_importFromIframe'] = finish;
  
      // ------------------------------------------------------------------------
      // We are now ready to start.
      // ------------------------------------------------------------------------
  
      // see head section in this file for how to configure load_on_scroll
      function init() {
          if (load_on_scroll) {
              if (attachEvent) {
                  window.attachEvent('onscroll', look_for_trouble);
              } else {
                  window.addEventListener('scroll', look_for_trouble, false);
              }
          } else {
              load_and_append();
          }
      }
  
      // we are using window.onload since we want "everything" to run
      // in the first screeen before we continue.
      if (attachEvent) {
          window.attachEvent('onload', init);
      } else {
          window.addEventListener('load', init, false);
      }
  
      // ------------------------------------------------------------------------
      // the script has started. Below functions are supporting it.
      // ------------------------------------------------------------------------
  
      // loaded in load_and_append after a successful ajax call.
      function append(txt, src) {
          // remove previously #load-more-unlimited-content links since 
          // it i not needed anymore.
          (function(elm_to_remove){ 
              elm_to_remove.parentNode.removeChild(elm_to_remove); 
          })(document.getElementById('load-more-unlimited-content'));
  
          console.log('install() begin');
          install(txt, src);
          console.log('install() done');
      }
  
      /**
       * cleaning function to strip unecessary tags(oup) out.
       * also attach and execute scripts with the help of an 
       * handy little snippet.
       */
      function install(ajax_result, src) {
          var acc_elm;        // final wrapper DIV,
          var acc_class;      // and it's unique class.
  
          // remove the footer since we don't want that in our result.
          ajax_result = ajax_result.match(/^([\n\s\S]+?)&lt;div id="mainBottom/im)
                      || ['', ajax_result];
  
          // rename #startPageContainer to avoid css conflicts.
          ajax_result = ajax_result[1].replace(/startpageContainer/m, 
                                  'startPageContainer_' 
                                  + Math.floor(Math.random() * 1000));        
  
          ajax_result = ajax_result.replace(/&lt;scr/ig, '\x3Cscr').replace(/&lt;\/scr/ig, '\x3C/scr');
  
          acc_class = 'aCC-' + src.match(/:\/\/.+?\/(.+?)\?/)[1].replace(/[\/.]/g, '_');
          acc_class += ' aCC'+ ++callsCount;
  
          acc_class = 'allColumnsContainer ' + acc_class;
  
          // mount ajax response in a temporary iframe 
          // and send the markup upwards when done. by doing 
          // this, all scripts in the ajax response is executed 
          // correctly.
          console.log('iframe begin');
          (function(iframe_container){
              var iframe_window;  // reference
              var splitted;       // for cross browser script execution
  
              iframe_window = getIFrameWindow(document.getElementById('unlimited-loader'));
  
              iframe_window.document.open();
  
              // open wrappers DIVs.
              iframe_window.document.write(
                  '&lt;div class="' + acc_class + 
                  '"&gt;&lt;div class="allColumnsContainer-inner"&gt;');
  
              // now comes a tricky part: all but IE will execute
              // script tags without any complains. To make the
              // last stubborn one work with us, we need to split 
              // strings to mimic the rusty ol':
              //       '&lt;scr' + 'ipt&gt;doAmazingStuff()&lt;/scr' + 'ipt&gt;';
              splitted = ajax_result.split('&lt;scr');
  
              // first chunk can be added right away.
              iframe_window.document.write(splitted[0]);
  
              // we are done now unless there was a script in 
              // the ajax response, which we know if we have more
              // than one chunk.
              if (splitted.length &gt; 1) {
                  for (var extracted, i = 1, max = splitted.length; i &lt; max; i++) {
                      // this is necessary since we need to 
                      // split the end tags as well.
                      extracted = splitted[i].split('&lt;/scr');
  
                      // now we can put it together
                      iframe_window.document.write('&lt;scr' 
                          + extracted[0] + '&lt;/scr' + extracted[1]);
                  }
              }
  
              // close wrapper DIVs
              iframe_window.document.write('&lt;/div&gt;&lt;/div&gt;');
  
              // finally, we ask the iframe to send the html 
              // up to the parent.
              iframe_window.document.write('&lt;scr');
              iframe_window.document.write('ipt&gt;setTimeout(function(){parent.mkt_importFromIframe(this);}, 999);&lt;/scr' + 'ipt&gt;');
              iframe_window.document.write('&lt;h1&gt;bu!&lt;/h1&gt;');
  
              console.log('iframe document.close begin');
  
              console.log('iframe document.close done');
          })((function(){
              var div = document.createElement('div');
  
              // the iframe should be visually hidden so
              // lets add some css for that.
              div.style.position = "absolute";
              div.style.left = "-9999px";
              div.style.top = "-99px";
  
              div.id = 'mkt_iframe-container'; // do not change this!
  
              div.innerHTML = '&lt;iframe id="unlimited-loader" name="unlimited-loader" src="inner.html"&gt;&lt;/iframe&gt;';
  
              (function(scr){
                   scr.parentNode.insertBefore(div, scr);
              })(document.getElementsByTagName('script')[0]);
  
              return div;
          })());    
          console.log('iframe done');
      }
  
      /**
       * callback function which is called when we are using 
       * scrollbased loading and fires a scroll event.
       * It makes sure we are not loading anything
       * until it is necessary.
       */
      function look_for_trouble(e) {
          // first, check to see if we should continue.
          if (window.mkt_nothing_more_to_load || window.mkt_prevent_new_loading) { 
              return; // one or more locks is still active, so we wait.
          }
  
          // second, we only want to load new content 
          // if we are at the bottom of the page.
          if (getDocHeight() - getScrollTop() &lt;= window.outerHeight) {
              window.mkt_prevent_new_loading = true;
              load_and_append();
          }
      };
  
      //
      // borrowed functions.
      //
  
      // found at http://james.padolsey.com/javascript/get-document-height-cross-browser/
      function getDocHeight() {
          return Math.max(
              Math.max(document.body.scrollHeight, 
                  document.documentElement.scrollHeight),
              Math.max(document.body.offsetHeight, 
                  document.documentElement.offsetHeight),
              Math.max(document.body.clientHeight, 
                  document.documentElement.clientHeight)
          );
      }
  
      // found at http://stackoverflow.com/questions/871399/cross-browser-method-for-detecting-the-scrolltop-of-the-browser-window
      function getScrollTop(){
          if(typeof pageYOffset!= 'undefined'){
              //most browsers
              return pageYOffset;
          }
          else{
              var B= document.body; //IE 'quirks'
              var D= document.documentElement; //IE with doctype
              D= (D.clientHeight)? D: B;
              return D.scrollTop;
          }
      }
  
      // http://av5.com/docs/changing-parent-window-s-url-from-iframe-content.html
      function getIFrameWindow(iframe) {
          return (iframe.contentWindow) ? iframe.contentWindow : (iframe.contentDocument.document) ? iframe.contentDocument.document : iframe.contentDocument;
      }
  
      function getHTTPObject() {
          var xhr = false;//set to false, so if it fails, do nothing
          if(window.XMLHttpRequest) {//detect to see if browser allows this method
              var xhr = new XMLHttpRequest();//set var the new request
          } else if(window.ActiveXObject) {//detect to see if browser allows this method
              try {
                  var xhr = new ActiveXObject("Msxml2.XMLHTTP");//try this method first
              } catch(e) {//if it fails move onto the next
                  try {
                      var xhr = new ActiveXObject("Microsoft.XMLHTTP");//try this method next
                  } catch(e) {//if that also fails return false.
                      xhr = false;
                  }
              }
          }
          return xhr;//return the value of xhr
      }
  })(window, document);
  </code></pre>