I've tried many different ways to phrase this question to google et al with no luck. Not even sure the title of this question captures the nuance of the issue. I'll try to explain then show the experiment. I hope someone(s) will be able to point to some explanation of what's going on.

Given:

  • before the end of BODY, you have a script (A) that programmatically inserts a script element (using my preferred technique, document.createElement) into the document which references a remote-script (B)
  • remote-script B performs a document.write of any content (e.g. "hello, world")
  • before the end of BODY and just after script A you have a script (C) that references a remote-script which takes a while to load (e.g. 1s)

What will happen is that A executes, inserts B into the document and starts to download the resource. While B is downloading, C will execute and wait, because of the delay. While C is waiting, B is downloaded and executes; we have not yet hit DOMContentLoaded; document.readyState is still "loading". The document.write from B is ignored; gobbled up, as if we are post-DOMContentLoaded. C then finishes downloading and executes.

Experiment:

I am using Cuzillion to create the delay. If you check out the waterfall image, you'll also see the console.log message, which shows that everything is executed before the DOM hits "interactive" readyState (i.e. DOMContentLoaded).

What I expect as output in the browser is:

TOP
hello, world
hello again, world
BOTTOM

What I get as output is:

TOP
hello, world
BOTTOM

You'll notice in my experiment that I have added another script between what we would define as A and C. Call this A' I suppose; it shows that if you dynamically add a script that has text (i.e. not a remote script) which contains a document.write, the doc.write in A' WILL work.

Also, dummy.js and the CSS files come from JSFiddle. They are not the culprits; I can recreate this issue anywhere.

Things I know:

  • if you replace C with an IMG, there is no issue
  • if you replace C with an IFRAME, there is no issue
  • if you move A after C, there is no issue

Now:

Perhaps there is a perfectly valid reason for this. There must be since all of the browsers I've tested in seem to behave in roughly the same way. What I'd like to know is why? Any explanations, hints, and/or pointers are welcome. Even hints like "It's in the spec, dumby :)" I've got thick skin; I can handle it.

DISCLAIMER: I abhor document.write. My intention is not to support or bolster its use in any way. However, given the nature of my work, I have to work around it for now and this oddity sprung itself on me. Thus, I'd like to avoid comments along the line of "you shouldn't use document.write" because this, I already believe in :)

有帮助吗?

解决方案

Doing document.write from async-loaded scripts is not supported in HTML5, precisely because it's racy: you have no way to know whether your script will run before or after DOMContentLoaded. See http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#ignore-destructive-writes-counter and http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#dom-document-write step 2 and http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#execute-the-script-block step 3. The point being that having the write work if the script beats the race to DOMContentLoaded but be ignored if it loses the race would be pretty odd and would lead to pages sometimes working and sometimes not depending on network conditions.

其他提示

SEC7112: Script from https://raw.github.com/gist/2141272/1a6bf0111ce10d55e628e3736a9d381d82e8a780/external-with-docwrite.js was blocked due to mime type mismatch

This is your problem. The script is transferred as text/plain, which is not a valid MIME type for JavaScript.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top