Aleksandar Totic
Aleksandar Totic

Reputation: 2597

Why don't cloneNode <script> tags execute?

Cloned <script> tags do not execute. Why?

Example:

<script id="hello">
  console.log("hello execution count ", window.helloCount++);
</script>

<script id="action">
  document.body.appendChild(
    document.getElementById('hello').cloneNode(true));
  console.log('cloned the script');
</script>

After execution, there are two hello scripts in the document, but only one has executed.

http://jsbin.com/zuxoro/1/edit?html,console,output

This is part of a larger problem I am working on, so I know it is a dumb thing to do.

Upvotes: 20

Views: 3011

Answers (3)

apsillers
apsillers

Reputation: 115950

This behavior is required by the W3C HTML5 specification.

Each <script> element has a property flag called "already started". The specification says:

Initially, script elements must have this flag unset (script blocks, when created, are not "already started"). The cloning steps for script elements must set the "already started" flag on the copy if it is set on the element being cloned.

And then, later:

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.

The solution is simply not to clone script elements, but to create completely new elements that are populated with the same content.

Upvotes: 15

Barmar
Barmar

Reputation: 781255

I don't know why it doesn't work with cloneNode, but you can achieve the same result by copying the innerHTML to a new script node.

var clone = document.createElement('script');
clone.innerHTML = document.getElementById('hello').innerHTML;
document.body.appendChild(clone);
console.log('copied the script');
<script>
  window.helloCount = 1;
</script>
<script id="hello">
  console.log("hello execution count ", window.helloCount++);
</script>
<div>Copied scripts do execute</div>

Upvotes: 5

c-smile
c-smile

Reputation: 27460

In principle browser does the following when it executes <script> on the page:

If script <script> was not executed before it does the following:

  1. Takes text from the <script>;
  2. Calls eval(thatScriptText);
  3. Marks the <script> DOM node as executed;

When you clone the node it gets that internal "executed" flag too, it prevents the script from further executions.

Solution: if you want script to be re-executed do steps #1 and #2. Cloning is not required in this case.

Upvotes: 2

Related Questions