21

I keep reading the same thing:

"Storing property values directly on DOM elements is risky because of possible memory leaks."

But can someone explain these risks in more detail?

zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • 20
    where have you been reading this? – tybro0103 Oct 09 '12 at 15:16
  • ?? i think exactly the opposite. the most common problem with memory leaks normally is the circular reference. read the comments in [http://perfectionkills.com/understanding-delete/](http://perfectionkills.com/understanding-delete/) –  Oct 09 '12 at 15:19
  • I'm with @tybro0103 on this one; don't believe everything you read on the net. Storing data in `data-` attributes is not going to cause memory-leaks in and of itself. That being said, I'm upvoting @Werner's answer below for quoting a reputable source. – Sampson Oct 09 '12 at 15:21
  • Please cite your source. – zzzzBov Oct 09 '12 at 15:27
  • @zzzzBov: I think the source is [this answer](http://stackoverflow.com/a/12801522/1689607) to the previous question. – I Hate Lazy Oct 09 '12 at 17:46

2 Answers2

16

(By attribute, I assume you are referring to properties on DOM elements.)

Are custom properties on DOM elements safe?

Some browsers have not cleaned up DOM elements very well when destroyed. References to other elements, the same element, or large sets of data were therefore retained, causing leaks. I believe this is largely resolved in newer browsers.

In any case, storing small amounts of data on an element is innocuous, and can be very convenient, so take that warning with a grain of salt.


Is using jQuery's .data() a safe alternative?

Not especially. Storing data using jQuery's custom data store has its own potential for memory leaks, and unfortunately they don't merely affect old browsers.

In order to avoid leaks, you'd need to be absolutely certain you clean an element's .data() when destroying an element. This is automatic when you use jQuery to destroy the element, but if you don't, you'll have memory leaks that affect every browser.


What are some examples that can cause leaks?

Let's say that there's a bunch of .data() linked to the #foo element. If we use jQuery methods to remove the element, we're safe:

$("#foo").remove(); // associated .data() will be cleaned automatically

But if we do this, we have a cross-browser compatible leak:

var foo = document.getElementById("foo");
foo.parentNode.removeChild(foo);

Or if #foo is a descendant of some other element whose content is being cleared without jQuery, it would be the same issue.

otherElement.innerHTML = "";

In both cases, jQuery was not used to remove #foo, so its .data() is permanently disassociated from the element, and our application has a leak.


So if I never use the DOM API directly, I'm safe?

You're safer, but another way this can happen is if we load more than one DOM manipulation library. Consider that jQuery helps us do this with the following code:

var $jq = jQuery.noConflict();

Now we can allow $ to refer to prototypejs or mootools, and jQuery is referenced by $jq.

The trouble is that those other libraries will not clean up data that was set by jQuery, because they don't know about it.

So if jQuery has some data on #foo, and mootools is used to destroy that element, we have our memory leak.


What if I never use .data() in jQuery? Does that make me safe?

Sadly, no. jQuery uses the same .data() mechanism to store other data, like event handlers. Therefore even if you never make a call to .data() to associate some custom data with an element, you can still have memory leaks caused by the examples above.

Most of the time you may not notice the leaks, but depending on the nature of the code, they can eventually grow large enough to be a problem.

I Hate Lazy
  • 47,415
  • 13
  • 86
  • 77
  • 1
    Can you explain what you mean when you say "clean an element's .data() using jQuery when you destroy the element" –  Oct 09 '12 at 15:32
  • @Anne: Yes. All data, handlers, etc that are associated with an element are stored in a single data store called `jQuery.cache`. The link between an element and its data in the store is a serial number that jQuery puts directly on the element. If you use jQuery to destroy an element, jQuery will look up the data in the store, and remove it. Trouble is that if you don't use jQuery to destroy an element, then the serial number is lost with the element, and the associated data in `jQuery.cache` is permanently orphaned. IMO, this is far more serious than storing a little data on an element. – I Hate Lazy Oct 09 '12 at 15:35
12

According to the jQuery documentation:

In Internet Explorer prior to version 9, using .prop() to set a DOM element property to anything other than a simple primitive value (number, string, or boolean) can cause memory leaks if the property is not removed (using .removeProp()) before the DOM element is removed from the document. To safely set values on DOM objects without memory leaks, use .data().

Sampson
  • 265,109
  • 74
  • 539
  • 565
Werner Kvalem Vesterås
  • 10,226
  • 5
  • 43
  • 50
  • I was meaning my use of $('#id').attr('data-xx','yy'); Is .prop something else? –  Oct 09 '12 at 15:33
  • I find the accepted answer on the following link to be a very good explanation on the difference between .attr() & .prop(): http://stackoverflow.com/questions/5874652/prop-vs-attr – Werner Kvalem Vesterås Oct 09 '12 at 15:36