Browser crashes with below code.What is wrong in below code.

K

kiran

Hi,

All my browser are either hanging or crashing due to below code,Any ideas as what is happening.While debugging my jsp page, I narrowed down to below clone method of jquery.Also as per my understanding there are some tags in HTML5 which do not require to have end tags, does UL require end tag as per HTML5 ?.
Again I am no expert in Javascript but again trying to get my hands dirty either by reading books or trying on my own by googling here and there on net.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Simple Test Case</title>
</head>

<body>
<ul>
<li>Test1</li>
<li>Test2</li>
<li>Test3</li>
<li>Test4</li>
<li>Test5</li>
<li>Test6</li>
</ul>

<script type="text/javascript" src="js/jquery-1.6.4.js"></script>
<script>
jQuery('ul').clone().appendTo('body');
</script>
</body>
</html>
 
K

kiran

This is code which crashes browsers,below code do not have end UL tag.Though having end UL fixes the crash,but wanted to get this confirmed.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Simple Test Case</title>
</head>

<body>
<ul>
<li>Test1</li>
<li>Test2</li>
<li>Test3</li>
<li>Test4</li>
<li>Test5</li>
<li>Test6</li>


<script type="text/javascript" src="js/jquery-1.6.4.js"></script>
<script>
jQuery('ul').clone().appendTo('body');
</script>
</body>
</html>
 
S

Swifty

This is code which crashes browsers,below code do not have end UL tag.Though having end UL fixes the crash,but wanted to get this confirmed.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Simple Test Case</title>
</head>

<body>
<ul>
<li>Test1</li>
<li>Test2</li>
<li>Test3</li>
<li>Test4</li>
<li>Test5</li>
<li>Test6</li>


<script type="text/javascript" src="js/jquery-1.6.4.js"></script>
<script>
jQuery('ul').clone().appendTo('body');
</script>
</body>
</html>

Having little knowledge of Javascript, and none of jQuery, this looks
fairly obvious.

The jQuery statement seems to be cloning your "ul" element and
appending it to the body.

<ul> requires a closing </ul>.

So, the cloning starts at the <ul>, and failing to find the closing
</ul> it clones to the end of the HTML, including the cloning request.
The cloned jQuery statement then sets about its work, and the process
loops until you run out of memory.
 
R

RobG

Having little knowledge of Javascript, and none of jQuery, this looks
fairly obvious.

The jQuery statement seems to be cloning your "ul" element and
appending it to the body.

<ul> requires a closing </ul>.

So, the cloning starts at the <ul>, and failing to find the closing
</ul> it clones to the end of the HTML, including the cloning request.
The cloned jQuery statement then sets about its work, and the process
loops until you run out of memory.

An interesting hypothesis, however a test in Safari and Firefox shows
that while a deep clone of an element that contains a script element
also clones the script, it isn't executed. e.g.

<ul>
<li>
<script>console.log('hey');</script>
</ul>
<script>
var el = document.getElementsByTagName('ul')[0].cloneNode(true);
document.body.appendChild(el);
</script>

only prints one "hey" in the console.

Similarly, placing a script element inside an element that clones the
containing element doesn't cause an endless loop of clones, e.g.

<ul>
<li>item
<script>console.log('hey');</script>
<script>
var el = document.getElementsByTagName('ul')[0].cloneNode(true);
document.body.appendChild(el);
</script>
</ul>

Leaving off the closing UL tag doesn't make any difference. In fact,
if an LI is added after the script element, it's not included in the
clone. So it would appear that the UL and its child nodes up to the
script are cloned, then appended after the the browser has performed
its error correction to close the UL.

I haven't tested the OPs claims regarding jQuery's behaviour.
 
A

Arno Welzel

kiran, 2011-12-04 06:02:
This is code which crashes browsers,below code do not have end UL tag.Though having end UL fixes the crash,but wanted to get this confirmed.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Simple Test Case</title>
</head>

<body>
<ul>
<li>Test1</li>
<li>Test2</li>
<li>Test3</li>
<li>Test4</li>
<li>Test5</li>
<li>Test6</li>


<script type="text/javascript" src="js/jquery-1.6.4.js"></script>
<script>
jQuery('ul').clone().appendTo('body');
</script>
</body>
</html>

Confirmed.

I assume the problem is caused by the missing end tag for the list,
since list is then not closed yet.

clone() will collect existing elements. appendTo() will then append
thoes elements. I did not have a look to the code of jquery, but i
assume clone() will also see those elements which get created by appendTo().

So this it what happens:

- clone() will fetch "Test1"
- appendTo() will create a copy of "Test1" and the end of the list
- clone() will fetch "Test2"
- appendTo() will create a copy of "Test2" and the end of the list
....
- clone() will fetch "Test6"
- appendTo() will create a copy of "Test6" and the end of the list

and NOW clone() will see the first copy of "Test1" since the list is not
closed by </ul> - therefore the whole process continues until the
browser crashes. Well - at least my FF 8.0.1 asks me after a while if i
want to stop the script ;-)
 
R

RobG

kiran, 2011-12-04 06:02:



Confirmed.

I assume the problem is caused by the missing end tag for the list,
since list is then not closed yet.

Nothing to do with the missing closing tag, the browser deals with
that. Adding a closing tag doesn't fix the issue. Moving the script
element out of the UL does.

clone() will collect existing elements.

The expression jQuery('ul') does that, clone calls clone the clone
method of a jQuery object, which then calls .map which calls
jQuery.clone() which finally gets around to calling clonNode(true) -
and then does lost of weirdness, probably trying to fix "edge cases".

appendTo() will then append
thoes elements. I did not have a look to the code of jquery, but i
assume clone() will also see those elements which get created by appendTo().

There is certainly some weirdness going on. If you look at the code,
jQuery always creates a deep clone, then tries to fix attached events
(since those added with attachEvent are cloned but those added with
addEventListener aren't) and tries to fix obscure differences with
attributes on some elements.

In amongst all that, it gets lost. A jQuery object calls this
function:

clone: function( dataAndEvents, deepDataAndEvents ) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ?
dataAndEvents : deepDataAndEvents;

return this.map( function () {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
});
},

which calls map and passes it jQuery.clone as the "callback"

map: function( callback ) {
return this.pushStack( jQuery.map(this, function( elem, i ) {
return callback.call( elem, i, elem );
}));
},

and jQuery.clone is:

jQuery.extend({
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
var clone = elem.cloneNode(true),
srcElements,
destElements,
i;

if ( (!jQuery.support.noCloneEvent || !
jQuery.support.noCloneChecked) &&
(elem.nodeType === 1 || elem.nodeType === 11) &&
!jQuery.isXMLDoc(elem) ) {
// IE copies events bound via attachEvent when using cloneNode.
// Calling detachEvent on the clone will also remove the events
// from the original. In order to get around this, we use some
// proprietary methods to clear the events. Thanks to MooTools
// guys for this hotness.

cloneFixAttributes( elem, clone );

// Using Sizzle here is crazy slow, so we use
getElementsByTagName
// instead
srcElements = getAll( elem );
destElements = getAll( clone );

// Weird iteration because IE will replace the length property
// with an element if you are cloning the body and one of the
// elements on the page has a name or id of "length"
for ( i = 0; srcElements; ++i ) {
// Ensure that the destination node is not null; Fixes #9587
if ( destElements ) {
cloneFixAttributes( srcElements, destElements );
}
}
}

// Copy the events from the original to the clone
if ( dataAndEvents ) {
cloneCopyEvent( elem, clone );

if ( deepDataAndEvents ) {
srcElements = getAll( elem );
destElements = getAll( clone );

for ( i = 0; srcElements; ++i ) {
cloneCopyEvent( srcElements, destElements );
}
}
}

srcElements = destElements = null;

// Return the cloned set
return clone;
},

In true jQuery style, it disappears up its own arse in convoluted
calls to all sorts of functions to "fix" things along the way. Someone
might care to trawl through all that to find the issue but I'm not
bothered.

So this it what happens:

No point guessing, it has nothing to do with the missing closing tag.
It is certainly something to do with the script element being within
the element being cloned, but why is for someone else to discover.

Care to log it as a bug? :)
 
K

kiran

Thanks Rob and everyone for confirming this.I will bring this to the notice of jQuery team and see what they have to say on this.
 
E

Evertjan.

kiran wrote on 07 dec 2011 in comp.lang.javascript:
They feel its code issue and not an issue with jQuery.

So jQuery is not just code?

That it is code-to-be-avoided-at-all-cost is clear to me.
 
R

RobG

Doctor, it hurts when I do this...

When "this" is something that should not hurt, it seems reasonable to
bring it to the attention of someone who might be able to explain why
does it hurt, if not fix it.

Can you explain why browsers do not execute script elements in cloned
nodes when using the DOM cloneNode method, but when using jQuery's
clone function, they do?
 
S

Scott Sauyet

RobG said:
When "this" is something that should not hurt, it seems reasonable to
bring it to the attention of someone who might be able to explain why
does it hurt, if not fix it.

Sorry, I should have put quotes around that. It was my attempt to
summarize the responses from the jQuery community, not my own view.

Can you explain why browsers do not execute script elements in cloned
nodes when using the DOM cloneNode method, but when using jQuery's
clone function, they do?

Yes.

But I'm not sure I want to, because it might make it sound as though I
agree with jQuery's decision on this. So, with the caveat in mind
that I don't agree with their decision, let me first point out that
jQuery is just Javascript. The DOM `cloneNode` method is still
available. So they have to decide whether their method is just a thin
wrapper around `cloneNode` or whether it is meant to do something
different. They have chosen to do more. For one thing, jQuery copies
over not just the DOM material, but also, optionally, copies the event
handlers on the node and, with another option, on its descendents. I
like this decision they made, but it could also lead to another
question about "Why does this jQuery example differ from this parallel
DOM one?"

They also decided to run the scripts that were included in the copy
(presumably only after the copy is attached to the DOM, although I
haven't looked closely.) This allows for the style of dynamic
generation that puts SCRIPT markup immediately after the markup for
elements on which it will operate, something like:

<div id="template">
<div class="xyz">...</div>
<script>process($(".xzy:last")[0]);</script>
</div>

$("#template").clone(true).appendTo(someContainer);

With this, whatever server-side decisions that were made about how to
handle this templated content are duplicated when it's cloned.

This is not a style of development I like, and I don't really see a
reason for jQuery to cater to what I see as poor practice, but I do
understand it, and I've been on projects that used it heavily.

So I suppose I've only answered half the question. This is why jQuery
does run the scripts when cloning. As to why browsers don't do so in
cloneNode, I can't really say.


I also would like to point out that this code:

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

is not the most direct port of the jQuery code:

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


This naive port would be semantically a little closer:

<div>div
<script>
var els = document.getElementsByTagName('div');
for (var i = 0; i < els.length; i++) {
document.body.appendChild(els.cloneNode(true));
}
</script>
</div>

Of course because of the live NodeList, that one also has an infinite
loop problem. It's a different issue than in the jQuery code, but
it's still a real issue.

-- Scott
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top