Skip to content

Data: avoid using delete on DOM nodes #1664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

jbedard
Copy link
Contributor

@jbedard jbedard commented Sep 24, 2014

This is similar to #1662 but for jQuery 1.x which reproduces https://code.google.com/p/chromium/issues/detail?id=378607 in cleanData by using delete on DOM nodes. I have found this issue worse then the jQuery2 version because cleanData often runs on large groups of nodes at once (such as when changing pages in a SPA). If every node (with data) reproduces the chrome issue it can cause memory usage to spike very high and cause significant performance issues. I have seen pages spike from 15m to 150m while transitioning pages in a SPA, combined with https://code.google.com/p/v8/issues/detail?id=2073 that use case often crashes the browser.

The easiest way to reproduce it, in the chrome console (on any page, a blank one makes the memory snapshot easier to read):

var div = document.createElement("div");
div.jQuery123 = 1;
*heap snapshot #1*
delete div.jQuery123;
*heap snapshot #2*

If you find the detached div element in the heap snapshot it is about 150 bytes in snapshot 1, in snapshot 2 I'm normally seeing it around 6300 bytes.

I'm having trouble testing this properly in oldIE so I'm not 100% sure if the current commit covers oldIE correctly. I think setting elem[ $.expando ] = undefined will just change the expando attribute to jQuery###="undefined" in the DOM, so maybe we need a support test for that and an extra .removeAttribute( internalKey )?

@jbedard
Copy link
Contributor Author

jbedard commented Sep 24, 2014

/cc @markelog, @rwaldron, @gibson042 since you were all interested in the jQuery2 issue

actual = div[ jQuery.expando ];
}
equal( actual, expected, message );
equal( div[ jQuery.expando ], undefined, message );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strictEqual

@jbedard
Copy link
Contributor Author

jbedard commented Sep 25, 2014

I've added the removeAttr back, but the support test is different now since we never actually want to delete.

Here's a jsperf that tests clone+data+remove of 1000 nodes: http://jsperf.com/cleandata/3
And the other jsperf that highlights just the chrome bug: http://jsperf.com/chrome-dom-delete

@jbedard
Copy link
Contributor Author

jbedard commented Sep 25, 2014

Or maybe http://jsperf.com/cleandata/4 is more realistic where the .remove is on the parent. Seems about the same though.

} else {
elem[ internalKey ] = null;
elem[ internalKey ] = undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend also updating the analogous line in internalRemoveData.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In internalRemoveData it does...

if ( isNode ) => cleanData( ... )
else if ( support.deleteExpando || !isWindow ) => delete
else => assign null

Doesn't support.deleteExpando mean that it is safe to delete from nodes? But in this case we already know it is not a node... Or does support.deleteExpando also test for more general non-node delete issues?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave the conditions alone; just change null to undefined there as you have done here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, although I still don't understand that deleteExpando check, but I guess that is unrelated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deleteExpando there is to protect against throwing an exception when the context object is a window.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see, and the deleteExpando test on a div tests for the same issue as deleting from the window (and leaking a test var onto the window would be lame...). Thanks!

@gibson042
Copy link
Member

http://jsperf.com/cleandata/4 is exactly what I was looking for, and clearly shows the performance impact on Webkit and especially Blink. Given their severity, I'd rather leave an undefined property than take the hit. Does anyone else want to weigh in (@rwaldron, @dmethvin, ...)?

// IE does not allow us to delete expando properties from nodes
// IE creates expando attributes along with the property
// IE does not have a removeAttribute function on Document nodes
// Chrome has issues deleting from nodes (https://code.google.com/p/chromium/issues/detail?id=378607)
// we must handle all of these cases
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall this line remain with the IE comments, or just remove it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be removed.

@jbedard
Copy link
Contributor Author

jbedard commented Sep 26, 2014

I've made the changes, let me know if I missed anything. Just need to add the new attrProp to the support tests which should be pushed in a few mins...

Ref chromium issue 378607
@markelog
Copy link
Member

markelog commented Dec 3, 2014

since this is one of the last PR's to 1.x-master and it seems all issues has been dealt with, i would like to merge it

@dmethvin
Copy link
Member

dmethvin commented Dec 3, 2014

Yes, let's merge this. It looks like the underlying Chrome bug has been there a while so there is no guarantee they will fix it soon. This patch mentions the bug so we can review and change it in the future if it ever gets fixed. Thanks @jbedard!

@timmywil
Copy link
Member

Closed by 9d1d90e

@lock lock bot locked as resolved and limited conversation to collaborators Jan 19, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants