4

Why does the following jQuery code cause my browser to hang?

Caution: do not run this unless you are prepared to force quit your browser

<!DOCTYPE HTML> 
  <title>Simple clone</title> 
  <script type="text/javascript" src="jquery.js"></script> 

  <div>
    <script>$('div').clone().appendTo('body');</script>
  </div>

Edit

For those in the "infinite loop" camp, that should not be an issue. A perfectly safe (non-jQuery) version is:

  <div>div
    <script>
      var el = document.getElementsByTagName('div')[0];
      document.body.appendChild(el.cloneNode(true));
    </script>
  </div>

So the issue is specifically related to how jQuery does clones.

Edit 2

It seems that jQuery causes script elements in clones to be executed. That isn't standard behaviour and is something about how jQuery does clones that is quite unexpected.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • 7
    It seems kind-of obvious... – Šime Vidas Dec 05 '11 at 00:51
  • 3
    Your cloning the function itself, creating an infinite loop, destroying the entire intertweetyfaceweb galaxy, distrupting the space-time continuum! – adeneo Dec 05 '11 at 00:52
  • The interesting question is why the non jQuery version doesn't cause an infinite loop – Raynos Dec 05 '11 at 01:15
  • @RobG It gets executed (twice) in my Chrome and Firefox: http://jsfiddle.net/vYZx4/ – Šime Vidas Dec 05 '11 at 01:15
  • @ŠimeVidas Why does this only get executed once? http://jsfiddle.net/vYZx4/1/ – Raynos Dec 05 '11 at 01:17
  • @RobG `appendTo` does something stupid : http://jsfiddle.net/vYZx4/3/ – Raynos Dec 05 '11 at 01:19
  • Hmmm... yes, jQuery executes script elements in clones. Great. – RobG Dec 05 '11 at 01:23
  • @RobG another reason not use jQuery? o/ – Raynos Dec 05 '11 at 01:26
  • 1
    http://www.aspiringcraftsman.com/2008/01/03/art-of-separation-of-concerns/ – Incognito Dec 05 '11 at 01:30
  • Try sticking this - '
    ' in jsFiddle and see it loop until it reaches a RangeError, I'd call that an infinite loop if I ever did see one!
    – adeneo Dec 05 '11 at 01:30
  • @RobG if you could link the spec where it says cloned script nodes shouldnt execute that would be great – Raynos Dec 05 '11 at 01:34
  • John Resig has answered [here](http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object) that only DOM elements will be cloned, and clone() will not clone javascript objects. A script tag is a DOM element, and is cloned and executed, as far as I know there is nothing that says otherwise. – adeneo Dec 05 '11 at 01:38
  • @adeneo WHATWG says otherwise "The first is a flag indicating whether or not the script block has been "already started". 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.". jQuery is simply wrong – Raynos Dec 05 '11 at 01:40
  • I agree that is it not the same as the native cloneNode function, however if it is wrong depends on what John Resig, Karl Svedberg and the other creators of the jQuery function intended it to do? – adeneo Dec 05 '11 at 01:45
  • 1
    @Raynos — HTML5 isn't a standard, much of it documents existing behaviour without saying that's what it's doing. The relevant standard ([DOM 3 Core](http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-3A0ED0A4)) doesn't say what should happen. However, given that the default behaviour of *cloneNode* is to **not** re-execute script elements (even though it clones them), then jQuery shouldn't do it either, even if the cloning script is inside the cloned element (I don't know why jQuery does it but it certainly isn't expected or designed behaviour). – RobG Dec 05 '11 at 02:48

2 Answers2

7

Because you're cloning a div that has inside of it a script that says to clone all divs. The original div's script that says to clone all divs is cloned too, and so on, ad infinitum

Of course you could do:

  <script type="text/javascript" src="jquery.js"></script> 
  <script type="text/javascript">
     $(function() {
        $('div').clone().appendTo('body');
     });
  </script>

  <div>
    Safe Now
  </div>
James Montagne
  • 77,516
  • 14
  • 110
  • 130
Adam Rackis
  • 82,527
  • 56
  • 270
  • 393
  • @James - thank you. Jeff has said not to make (supposedly) "trivial" edits, but I'm glad you did. – Adam Rackis Dec 05 '11 at 01:12
  • 3
    I knew that moving the script outside the element being cloned fixes the issue, the revelation is that jQuery (uniquely) causes scripts in cloned elements to be executed. – RobG Dec 05 '11 at 01:31
  • @Rob - fair enough - I apologize if that came off as condescending – Adam Rackis Dec 05 '11 at 01:32
2

It's an infinite loop. You're cloning a div which contains a script that clones 2 divs that have a script that clone 4...

James Montagne
  • 77,516
  • 14
  • 110
  • 130