Daniel Daniel - 2 months ago 7
HTML Question

Execution of dynamically generated Javascript

I was reading this question with the accepted answer being:


Script added by setting the innerHTML property of an element doesn't get executed.


But when I try to change the innerHTML of the first
<script>
tag in the following code:

<script></script>
<script>
document.querySelectorAll("script")[0].innerHTML = 'console.log("Test")';
</script>


I can see the injected code for the
<script>
element being executed (the
console.log()
function outputs Test).

Furthermore if I remove the first empty
<script>
tag (thus making the first element
[0]
refer to the script itself), the script is changed in the DOM, but the code is never executed.

<script>
document.querySelectorAll("script")[0].innerHTML = 'console.log("Test")';
</script>


What prompts this behaviour?

Answer

This is described in Scripting. When the script is being prepared,

  1. At step 2, the "parser-inserted" flag is removed:

    If the element has its "parser-inserted" flag set, then set was-parser-inserted to true and unset the element's "parser-inserted" flag.

  2. At step 4, before restoring the "parser-inserted" flag, the steps are aborted

    If the element has no src attribute, and its child nodes, if any, consist only of comment nodes and empty Text nodes, then the user agent must abort these steps at this point. The script is not executed.

Therefore, when you modify it, it will be prepared again:

When a script element that is not marked as being "parser-inserted" experiences one of the events listed in the following list, the user agent must synchronously prepare the script element:

Once the script ran, modifying the contents won't execute them, because script preparation will abort:

If the script element is marked as having "already started", then the user agent must abort these steps at this point. The script is not executed.

Comments