-
Notifications
You must be signed in to change notification settings - Fork 10
What to think about when replacing document.write
Many have attempted to replace document.write so it's possible to load ads and third-party content asynchronously, and very few have succeeded. It might even not be possible to write a perfect solution that solves any problem, but this is an attempt to document problems and solutions when replacing document.write. Please contribute if you know/find a problem:
-
Problem: Script contains document.write("<script src=...></script>"); but innerHTML doesn't execute the script.
- Solution: Parse the output. When a script tag is encountered, stop and load the script by injecting a script tag to head (remember attributes like charset). Continue to output where you left off when the script onload event triggers.
-
Problem: Script uses document.write to output an inline script
- If no type attribute or type="text/javascritp", eval the script
-
Problem: Script tag is split up in multiple write calls
- Example:
document.write("<scr"); document.write("ipt src='ad.js'></script>");
- Solution: Write the string content to a buffer, and flush it when a script is loaded. A callback on the script element has to have a reference to the domid to flush it to the correct position.
-
Problem: When using a write buffer, the a document.getElementById call right after it's inserted with document.write will not find the element.
- Example: document.write("<div id='foo'></div>"); document.getElementById("foo");
- Solution: Replace document.getElementById. If the original document.getElementById does not find the id, search the write buffer for an element with the id. Since scripts can modify this element, the changes have to be reflected to the document.
-
Problem: Internet Explorer (6, 7, 8?, 9?) does not allow document.getElementById before the DOM is ready. So it's not possible to inject the content while the page is loaded.
- Solution: Test if document.getElementById works before hijacking. Then either skip hijacking and let the IE users suffer, or delay writing out the buffers until the DOM is ready.
-
Problem: Scripts loaded asynchronously might bind to document.onload or DOMContentLoaded after they have been triggered. That will cause the callbacks to never be triggered.
- Solution (not tested in real life): When DOMContentLoaded is triggered on the document, add a wrapper for addEventListener and attachEvent on the document object. It should trigger the events with setTimeout so they're executed asynchronous.
-
Problem: Newlines before an <object>-tag cause issues when injecting with innerHTML in Internet Explorer.
- Solution: trim HTML before injecting
-
Problem: document.write("<scr"+"ipt src='someScript.js'></scr"+"ipt>"); someScript.expectScriptIsLoadedSynchronously(); /* will crash */- Solution: This is not a problem. For some reason the script doesn't load synchronously, so it's not possible for ads to use this technique. Test here: http://jsbin.com/agugeh/4/edit
-
Problem: Ads may use document.open() and document.close(). Browsers ignore these when called from within a blocking script, but not when the script is run non-blocking.
- Solution: Override document.open() with a method that returns the document (some browsers do), and document.close() with a function that does nothing. (Issue #10)