最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

iframe - Why won't this JavaScript (using document.open and document.write) work in Internet Explorer or Opera? - Stack

programmeradmin4浏览0评论

I desperately need some help on this one.

I've created a <script> that closely parallels, and reproduces the problem of, another more complex <script> that I've written elsewhere.

Here's what it does:

  • creates an <iframe> and inserts in into a <div> on the page
  • creates and appends a document to that <iframe>, which contains a <script> that defines a few functions (including a callback function and a function that loads an external <script> using AJAX)
  • the latter external script is just a call to the callback function, which calls a function that creates a document and appends it to the <iframe> it's in; this should effectively overwrite the <script>

The three files involved are:

  • .html (the main page)
  • .js (the first <script> that's loaded)
  • .js (the <script> loaded by jQuery's $.ajax() method)

This all works in Firefox, Safari, and Chrome. Where it breaks down is in Internet Explorer and Opera. What happens is that the render() function in main.js executes, and all three alerts are fired, but the document in the <iframe> is not overwritten. I can't tell what document is being created or written to, or if one is at all.

If I add debug code (like console.log(document)) in the beginning of the render() function, the working browsers seem to get a handle on the existing <iframe> document and list the properties included below. Internet Explorer also appears to find a document of some sort. I just can't tell why it's not letting me overwrite it.

Could it be an issue of scope? Maybe I'm using the document.write(), document.open() or document.close() methods improperly, and Firefox and a few other browsers are just letting me get away with it?

One possible clue: if I take the guts of the render() function out (i.e., just put them after load() in main.js), this works fine. That suggests to me that it's not how I'm using document.open(), etc., but that somehow by the time that the callback() function is executed, the document object is not available, or has gone out of scope, or something like that.

This has me totally stumped, and it's for a very important project with an impending deadline. I'm not above a hack or workaround if it gets me out of this jam. Any help or insight would be EXTREMELY appreciated!

console.log()'s listing of the document properties:

ATTRIBUTE_NODE: 2
CDATA_SECTION_NODE: 4
COMMENT_NODE: 8
DOCUMENT_FRAGMENT_NODE: 11
DOCUMENT_NODE: 9
DOCUMENT_POSITION_CONTAINED_BY: 16
DOCUMENT_POSITION_CONTAINS: 8
DOCUMENT_POSITION_DISCONNECTED: 1
DOCUMENT_POSITION_FOLLOWING: 4
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32
DOCUMENT_POSITION_PRECEDING: 2
DOCUMENT_TYPE_NODE: 10
ELEMENT_NODE: 1
ENTITY_NODE: 6
ENTITY_REFERENCE_NODE: 5
NOTATION_NODE: 12
PROCESSING_INSTRUCTION_NODE: 7
TEXT_NODE: 3
URL: "http://localhost/projects/test/ajax_loader/document_write/index.html"
activeElement: HTMLBodyElement
addEventListener: function addEventListener() {
adoptNode: function adoptNode() {
alinkColor: ""
all: HTMLCollection
anchors: HTMLCollection
appendChild: function appendChild() {
applets: HTMLCollection
attributes: null
baseURI: "http://localhost/projects/test/ajax_loader/document_write/index.html"
bgColor: ""
body: HTMLBodyElement
captureEvents: function captureEvents() {
characterSet: "UTF-8"
charset: "UTF-8"
childNodes: NodeList
clear: function clear() {
cloneNode: function cloneNode() {
close: function close() {
compareDocumentPosition: function compareDocumentPosition() {
compatMode: "BackCompat"
cookie: "__gads=ID=62bb88ab20ac9451:T=1256683145:S=ALNI_Mbso-nFjAvRzYhCSwhiuaDh84G8CA"
createAttribute: function createAttribute() {
createAttributeNS: function createAttributeNS() {
createCDATASection: function createCDATASection() {
createComment: function createComment() {
createDocumentFragment: function createDocumentFragment() {
createElement: function createElement() {
createElementNS: function createElementNS() {
createEntityReference: function createEntityReference() {
createEvent: function createEvent() {
createExpression: function createExpression() {
createNSResolver: function createNSResolver() {
createNodeIterator: function createNodeIterator() {
createProcessingInstruction: function createProcessingInstruction() {
createRange: function createRange() {
createTextNode: function createTextNode() {
createTreeWalker: function createTreeWalker() {
defaultCharset: "iso-8859-1"
defaultView: DOMWindow
designMode: "off"
dir: ""
dispatchEvent: function dispatchEvent() {
doctype: null
documentElement: HTMLHtmlElement
documentURI: "http://localhost/projects/test/ajax_loader/document_write/index.html"
domain: "localhost"
elementFromPoint: function elementFromPoint() {
embeds: HTMLCollection
evaluate: function evaluate() {
execCommand: function execCommand() {
fgColor: ""
firstChild: HTMLHtmlElement
forms: HTMLCollection
getCSSCanvasContext: function getCSSCanvasContext() {
getElementById: function getElementById() {
getElementsByClassName: function getElementsByClassName() {
getElementsByName: function getElementsByName() {
getElementsByTagName: function getElementsByTagName() {
getElementsByTagNameNS: function getElementsByTagNameNS() {
getOverrideStyle: function getOverrideStyle() {
getSelection: function getSelection() {
hasAttributes: function hasAttributes() {
hasChildNodes: function hasChildNodes() {
hasFocus: function hasFocus() {
height: 150
images: HTMLCollection
implementation: DOMImplementation
importNode: function importNode() {
inputEncoding: "UTF-8"
insertBefore: function insertBefore() {
isDefaultNamespace: function isDefaultNamespace() {
isEqualNode: function isEqualNode() {
isSameNode: function isSameNode() {
isSupported: function isSupported() {
jQuery1258269389622: 2
lastChild: HTMLHtmlElement
lastModified: ""
linkColor: ""
links: HTMLCollection
localName: null
location: Location
lookupNamespaceURI: function lookupNamespaceURI() {
lookupPrefix: function lookupPrefix() {
namespaceURI: null
nextSibling: null
nodeName: "#document"
nodeType: 9
nodeValue: null
normalize: function normalize() {
open: function open() {
ownerDocument: null
parentElement: null
parentNode: null
plugins: HTMLCollection
preferredStylesheetSet: null
prefix: null
previousSibling: null
queryCommandEnabled: function queryCommandEnabled() {
queryCommandIndeterm: function queryCommandIndeterm() {
queryCommandState: function queryCommandState() {
queryCommandSupported: function queryCommandSupported() {
queryCommandValue: function queryCommandValue() {
querySelector: function querySelector() {
querySelectorAll: function querySelectorAll() {
readyState: "complete"
referrer: "http://localhost/projects/test/ajax_loader/document_write/index.html"
releaseEvents: function releaseEvents() {
removeChild: function removeChild() {
removeEventListener: function removeEventListener() {
replaceChild: function replaceChild() {
scripts: HTMLCollection
selectedStylesheetSet: null
styleSheets: StyleSheetList
textContent: null
title: " Page"
vlinkColor: ""
width: 300
write: function write() {
writeln: function writeln() {
xmlEncoding: null
xmlStandalone: false
xmlVersion: null

I desperately need some help on this one.

I've created a <script> that closely parallels, and reproduces the problem of, another more complex <script> that I've written elsewhere.

Here's what it does:

  • creates an <iframe> and inserts in into a <div> on the page
  • creates and appends a document to that <iframe>, which contains a <script> that defines a few functions (including a callback function and a function that loads an external <script> using AJAX)
  • the latter external script is just a call to the callback function, which calls a function that creates a document and appends it to the <iframe> it's in; this should effectively overwrite the <script>

The three files involved are:

  • http://troy.onespot.com/static/document_write/index.html (the main page)
  • http://troy.onespot.com/static/document_write/main.js (the first <script> that's loaded)
  • http://troy.onespot.com/static/document_write/jsonp.js (the <script> loaded by jQuery's $.ajax() method)

This all works in Firefox, Safari, and Chrome. Where it breaks down is in Internet Explorer and Opera. What happens is that the render() function in main.js executes, and all three alerts are fired, but the document in the <iframe> is not overwritten. I can't tell what document is being created or written to, or if one is at all.

If I add debug code (like console.log(document)) in the beginning of the render() function, the working browsers seem to get a handle on the existing <iframe> document and list the properties included below. Internet Explorer also appears to find a document of some sort. I just can't tell why it's not letting me overwrite it.

Could it be an issue of scope? Maybe I'm using the document.write(), document.open() or document.close() methods improperly, and Firefox and a few other browsers are just letting me get away with it?

One possible clue: if I take the guts of the render() function out (i.e., just put them after load() in main.js), this works fine. That suggests to me that it's not how I'm using document.open(), etc., but that somehow by the time that the callback() function is executed, the document object is not available, or has gone out of scope, or something like that.

This has me totally stumped, and it's for a very important project with an impending deadline. I'm not above a hack or workaround if it gets me out of this jam. Any help or insight would be EXTREMELY appreciated!

console.log()'s listing of the document properties:

ATTRIBUTE_NODE: 2
CDATA_SECTION_NODE: 4
COMMENT_NODE: 8
DOCUMENT_FRAGMENT_NODE: 11
DOCUMENT_NODE: 9
DOCUMENT_POSITION_CONTAINED_BY: 16
DOCUMENT_POSITION_CONTAINS: 8
DOCUMENT_POSITION_DISCONNECTED: 1
DOCUMENT_POSITION_FOLLOWING: 4
DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: 32
DOCUMENT_POSITION_PRECEDING: 2
DOCUMENT_TYPE_NODE: 10
ELEMENT_NODE: 1
ENTITY_NODE: 6
ENTITY_REFERENCE_NODE: 5
NOTATION_NODE: 12
PROCESSING_INSTRUCTION_NODE: 7
TEXT_NODE: 3
URL: "http://localhost/projects/test/ajax_loader/document_write/index.html"
activeElement: HTMLBodyElement
addEventListener: function addEventListener() {
adoptNode: function adoptNode() {
alinkColor: ""
all: HTMLCollection
anchors: HTMLCollection
appendChild: function appendChild() {
applets: HTMLCollection
attributes: null
baseURI: "http://localhost/projects/test/ajax_loader/document_write/index.html"
bgColor: ""
body: HTMLBodyElement
captureEvents: function captureEvents() {
characterSet: "UTF-8"
charset: "UTF-8"
childNodes: NodeList
clear: function clear() {
cloneNode: function cloneNode() {
close: function close() {
compareDocumentPosition: function compareDocumentPosition() {
compatMode: "BackCompat"
cookie: "__gads=ID=62bb88ab20ac9451:T=1256683145:S=ALNI_Mbso-nFjAvRzYhCSwhiuaDh84G8CA"
createAttribute: function createAttribute() {
createAttributeNS: function createAttributeNS() {
createCDATASection: function createCDATASection() {
createComment: function createComment() {
createDocumentFragment: function createDocumentFragment() {
createElement: function createElement() {
createElementNS: function createElementNS() {
createEntityReference: function createEntityReference() {
createEvent: function createEvent() {
createExpression: function createExpression() {
createNSResolver: function createNSResolver() {
createNodeIterator: function createNodeIterator() {
createProcessingInstruction: function createProcessingInstruction() {
createRange: function createRange() {
createTextNode: function createTextNode() {
createTreeWalker: function createTreeWalker() {
defaultCharset: "iso-8859-1"
defaultView: DOMWindow
designMode: "off"
dir: ""
dispatchEvent: function dispatchEvent() {
doctype: null
documentElement: HTMLHtmlElement
documentURI: "http://localhost/projects/test/ajax_loader/document_write/index.html"
domain: "localhost"
elementFromPoint: function elementFromPoint() {
embeds: HTMLCollection
evaluate: function evaluate() {
execCommand: function execCommand() {
fgColor: ""
firstChild: HTMLHtmlElement
forms: HTMLCollection
getCSSCanvasContext: function getCSSCanvasContext() {
getElementById: function getElementById() {
getElementsByClassName: function getElementsByClassName() {
getElementsByName: function getElementsByName() {
getElementsByTagName: function getElementsByTagName() {
getElementsByTagNameNS: function getElementsByTagNameNS() {
getOverrideStyle: function getOverrideStyle() {
getSelection: function getSelection() {
hasAttributes: function hasAttributes() {
hasChildNodes: function hasChildNodes() {
hasFocus: function hasFocus() {
height: 150
images: HTMLCollection
implementation: DOMImplementation
importNode: function importNode() {
inputEncoding: "UTF-8"
insertBefore: function insertBefore() {
isDefaultNamespace: function isDefaultNamespace() {
isEqualNode: function isEqualNode() {
isSameNode: function isSameNode() {
isSupported: function isSupported() {
jQuery1258269389622: 2
lastChild: HTMLHtmlElement
lastModified: ""
linkColor: ""
links: HTMLCollection
localName: null
location: Location
lookupNamespaceURI: function lookupNamespaceURI() {
lookupPrefix: function lookupPrefix() {
namespaceURI: null
nextSibling: null
nodeName: "#document"
nodeType: 9
nodeValue: null
normalize: function normalize() {
open: function open() {
ownerDocument: null
parentElement: null
parentNode: null
plugins: HTMLCollection
preferredStylesheetSet: null
prefix: null
previousSibling: null
queryCommandEnabled: function queryCommandEnabled() {
queryCommandIndeterm: function queryCommandIndeterm() {
queryCommandState: function queryCommandState() {
queryCommandSupported: function queryCommandSupported() {
queryCommandValue: function queryCommandValue() {
querySelector: function querySelector() {
querySelectorAll: function querySelectorAll() {
readyState: "complete"
referrer: "http://localhost/projects/test/ajax_loader/document_write/index.html"
releaseEvents: function releaseEvents() {
removeChild: function removeChild() {
removeEventListener: function removeEventListener() {
replaceChild: function replaceChild() {
scripts: HTMLCollection
selectedStylesheetSet: null
styleSheets: StyleSheetList
textContent: null
title: " Page"
vlinkColor: ""
width: 300
write: function write() {
writeln: function writeln() {
xmlEncoding: null
xmlStandalone: false
xmlVersion: null
Share Improve this question edited Nov 15, 2009 at 13:35 Bungle asked Nov 15, 2009 at 7:30 BungleBungle 19.7k25 gold badges81 silver badges108 bronze badges 3
  • Are you experiencing any errors? – meder omuraliev Commented Nov 15, 2009 at 8:07
  • Hi meder - I am not seeing any errors in Internet Explorer or Opera. Both simply display the alert()s in the render() function, but don't do anything with the document in the <iframe>. – Bungle Commented Nov 15, 2009 at 8:25
  • take a look at: stackoverflow.com/questions/12467151/… – A. Binzxxxxxx Commented Oct 2, 2014 at 16:47
Add a comment  | 

6 Answers 6

Reset to default 11

if I take the guts of the render() function out (i.e., just put them after load() in main.js), this works fine.

Doesn't for me in IE8. If I lose the AJAX call completely and just call render() in main.js, I get the same result. In fact even if I replace the whole of main.js with just:

document.write('hello!');

with or without opening the document, the hello never appears!

If I put any timeout (even 0) on the call to render in main.js, it works. The timeout on the parent document, on the other hand, doesn't seem to be doing anything.

This extreme weirdness is caused by jQuery using a temporarily-inserted <script> tag to execute the code returned by in jsonp.js. If you simply call eval on the return value instead of having jQuery execute it, it works fine.

A related problem I found narrowing down the hello example is demonstrated by index.html:

<body>
<iframe name="foo"></iframe>
<script>
    var idoc= frames['foo'].document;
    idoc.open();
    idoc.write('<body><script src="main.js"><\/script>');
    idoc.close();
</script>

with main.js containing:

document.write('foo');

There is no foo written. (An inline script, on the other hand, was fine.)

If the idoc.close was omitted, it worked. If an additional idoc.write('bar') was added, the bar was written before foo in IE only. If I added both bar and the close call, IE crashed.

So to summarise, there are deep problems using document.write from inside a document that was itself written by document.write! Try to avoid it if at all possible. document.open can be a useful way to populate an iframe from a parent document, but you shouldn't really be needing it inside the child document, where you can use DOM methods on yourself.

As most people have already covered, IE has serious issues when attempting to do something simple like:

var doc = window.frames['your_frame'].document;
doc.open();
doc.write('<body><script src="external_resource.js"><\/script>');
doc.close();

After exhaustive searching, I found this this write-up which suggests using the javascript: URI scheme to insert the content into the iframe document. I've personally tested this solution in current versions of FF, Chrome, & Safari, as well as IE 7/8/9/10.

Borrowing from his examples, the following would work in place of my example above, and could be used to achieve what you're going after:

var iframe = window.frames['your_frame'];
var content = '<body><script src="external_resource.js"><\/script>';
iframe.contentWindow.contents = content;
iframe.src = 'javascript:window["contents"]';

I've heard it told that older versions of Safari don't handle the javascript: URI scheme very well, but I couldn't find a way to confirm as everyone using Safari seems to upgrade regularly. I also don't know if this runs into character limit problems for the URI in IE (since it is smaller than every other browser), but it's worth looking into for those of you suffering from a similar problem.

The fundamental problem is that in IE you can't do

iframe_document.open();
iframe_document.write('<script src="foo.js"><\/script>');
iframe_document.close();

Once document.close() is called on the iframe, IE seems to halt all javascript execution there. The js thread runs that document.close() while the http request for foo.js is outstanding, so the file is loaded but never executed.

I haven't found any way for the parent page to know that the script executing within the iframe is completely finished. One work-around is to make foo.js responsible for calling document.close() itself -- not very pleasant, but if you don't mind changing the called script, it does the trick.

Note: you must not document.write('document.close()') into the iframe directly: that causes IE to hang hard. But setTimeout(function(){document.close()}, 0) seems immune — as does a document.close() inside a loaded script sometimes. Ugh.

You should load the content of the iframe with the "src" attribute: the body of an iframe is used by browsers that don't support it to display an alternative message. You are, instead, injecting in the iframe a full, inline, html document and some browsers won't like it. More info here.

If you want to send messages to the iframe from the main document there's a nice tutorial on the John Resig's blog.

Would something as simple as:

function render(data) {
    document.body.innerHTML = data;
}

Solve your problems? Works in IE8/Win7.

That’s bizarre, and Michael Kleber is mistaken: all of the alerts come up just fine, so the problem isn’t that the script doesn’t execute. It does execute.

Observe the following changes to main.js:

$(document).ready(function() {

  // note that render() has to be moved into the window scope
  window.render = function(data) {
    document.open();
    alert('opened');
    document.write(data);
    alert('written');
    document.close();
    alert('closed');
  }

  function load() {
    $.ajax({
      url: 'jsonp.js',
      dataType: 'script'
    });
  }

  window.callback = function(data) {
    // does not work
    render(data);

    // works
    window.data = data;
    var t = setTimeout("render(data)", 0);
  }

  load();

});

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论