Why script elements created through DOMParser do not execute?
Asked Answered
M

1

17

I'm loading HTML in Ajax, parsing it with DOMParser and put all the childNodes of the document body into a document fragment.

When I add the fragment into the current document's body, <script> tags aren't executed.

I fiddled around and figured out that if I replace them with new dynamically created script tags, they get correctly executed.

I would like to know WHY?

E.g.

var html = "Some html with a script <script>alert('test');</script>";

var frag = parsePartialHtml(html);


fixScriptsSoTheyAreExecuted(frag);


document.body.appendChild(frag);


function fixScriptsSoTheyAreExecuted(el) {
  var scripts = el.querySelectorAll('script'),
      script, fixedScript, i, len;

  for (i = 0, len = scripts.length; i < len; i++) {
    script = scripts[i];

    fixedScript = document.createElement('script');
    fixedScript.type = script.type;
    if (script.innerHTML) fixedScript.innerHTML = script.innerHTML;
    else fixedScript.src = script.src;
    fixedScript.async = false;

    script.parentNode.replaceChild(fixedScript, script);
  }
}


function parsePartialHtml(html) {
  var doc = new DOMParser().parseFromString(html, 'text/html'),
      frag = document.createDocumentFragment(),
      childNodes = doc.body.childNodes;

  while (childNodes.length) frag.appendChild(childNodes[0]);

  return frag;
}

Without calling fixScriptsSoTheyAreExecuted, nothing will execute.

Another point that I find hard to follow is that if I try to simply clone the existing script nodes to create new ones using cloneNode, it doesn't work, which kinds of suggest that the script tags that were initially created by the DOMParser carries state that prevent them from being executed.

Monumental answered 23/1, 2015 at 15:9 Comment(3)
@Nit, That's not true at all. Dynamically added scripts are definitely executed. I'm asking why scripts dynamically created through the DOMParser object do not execute like the ones created using document.createElement.Monumental
Its also worth noting that this code also only works when you make the new fragment and move the nodes over. If you just try and append the parsed nodes directly to the main document, with or without the fix method, scripts wont executeNicosia
I find another way to execute the scripts -- create an iframe, set the src, then read frame.contentDocument.body.innerHTML -- but it only works in limited cases (CORS). #8340824Severin
T
28

This is explained in the DOM Parsing and Serialization spec:

parseFromString

The parseFromString(str, type) method must run these steps, depending on type:

Towle answered 10/2, 2015 at 17:11 Comment(1)
Thanks, I should have thought to look at the spec ;)Monumental

© 2022 - 2024 — McMap. All rights reserved.