Skip to content

An exquisite jQuery plugin for magical layouts that won't crash your browser

Notifications You must be signed in to change notification settings

aaronsakowski/isotope-leak-free

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Isotope (leak free)

Isotope is a cool jQuery plugin that uses lots of other peoples' code to do lots of fancy animated arrangement, filtering and sorting. Unfortunately, it also leaks memory like a fucking sieve, and its author has expressed a complete lack of interest in remediating this situation despite having already authored a fix, so here's a fork for people who will get fired if they let their users' browsers crash for the sake of eye candy because they're not paid to build standalone corporate vanity pages for ad agencies.

The Problem

In a word: Expandos. Despite being the scourge of all web programming for many a year (remember why everyone ran away from Prototype screaming?), they're occasionally necessary in cases where you really, really need persistent data attached to a specific DOM object. Isotope certainly requires this for much of its state awareness, so it keeps track of lists of atoms--which are basically cutesy synonyms for DOM objects.

Where Isotope goes horribly wrong is in committing a textbook JavaScript sin by assigning the results of jQuery selector operations (specifically not and filter) directly to these expando lists. Every jQuery selector operation returns an array with an extra prevObject attribute. This attribute contains the complete result set of the selector--including the actual DOM objects selected--thusly supplying the magic necessary for its amazingly popular chaining mechanism to work.

Check it out on your console:

leaks

One of many offenses littered throughout the Isotope code would look like:

this.$allAtoms = this.$allAtoms.not( $content );

Let's think about what that means for a minute. We've got ourselves an Isotope-ified DOM object--for all intents and purposes: this--and it's got some expando data attached to it called $allAtoms, which is a list of all of this's child nodes that Isotope has installed itself. We're running $allAtoms through not in order to filter something undesireable out of it and re-assigning the result of that directly to $allAtoms.

The result of that not contains another prevObject attribute, which contains the result of jQuery's selection efforts. Again, that will be an array of child nodes of this in every case, so this will be retaining nested chains of cyclical references to those elements no matter how many times they're removed.

leaks

But it gets worse because this re-filtering and re-assignment process happens repeatedly and the cyclical references they produce predictably snowball. After just a few Isotope insertion/removal cycles, you'll have

this.$allAtoms.prevObject.prevObject.prevObject.prevObject

and so on and so forth. Don't believe me? Ask Chrome's heap inspector:

leaks

Every one of those detached elements has outlived its usefulness and will never be seen again, but since all of their prevObjects contain references to every single DOM element that's ever been inserted into the Isotope container, and each one of them refers to yet another incarnation of the same array, those zombie elements will never be freed. Each part of the whole contains multiple copies of the whole and all of its parts, including itself. That's very holographic, but probably not at all what any sane person wants since JavaScript's GC is refcounted.

If we're dealing with complicated nodes full of canvases and whatnot, you can easily build a staircase to 300MB of RAM consumption or more in just a few minutes of application use if you're adding and removing things on an ongoing basis.

leaks

Upon reading that comment, four engineers proceeded to slap themselves in unison. It's an honest mistake, but refusing to fix it is honestly, offensively stupid.

The unfortunate reality is that the more you use Isotope, the more shit you leave floating around in browser memory. The more shit you leave floating around in browser memory, the slower your app runs. You'll probably crash the whole goddamned browser, too, but hey, why would a rockstar ninja Twitter employee need to take that seriously? Computers have all the memory in the world these days and there just aren't enough hours in the day to blog about golden ratios and solve problems that don't involve helping deviant miscreants share seven second iPhone videos of their misshapen genitalia with the world; fuck responsible coding and gimme my $50. P.S. What's a leak?

The Solution

The fix is simple: STOP ASSIGNING RAW JQUERY SELECTOR RESULTS TO EXPANDO PROPERTIES ON THE THINGS THEY WERE SELECTING! Really. That's all it takes. It's not even a heavily guarded industry secret or anything. Here's a really long, really thorough paper about it from IBM:

http://www.ibm.com/developerworks/web/library/wa-memleak/

After plugging this horrible hole, things look much better. When GC runs, all the abandoned content is reaped exactly as it should be:

leakfree

An admittedly better solution would be to just stop using Isotope, but we all have to ship at the end of the day, and the 20+ hours I wasted tracking this idiocy back to its source was ultimately less expensive than replacing the functionality I needed with something more specialized.

Linters can only do so much, kids.


Original work Copyright (c) 2011-2012 David DeSandro / Metafizzy LLC and all the other people he copied and pasted from.


And here's my license which entitles me to use all of this code in any commercial project I like:

Dec 7, 2012 10:56:20 PST | Receipt No: 2542-5500-0733-6758


Hello Nathan Duran,

You sent a payment of $25.00 USD to Metafizzy.
This charge will appear on your credit card statement as payment to PAYPAL *METAFIZZY.

----------------------------------------------------------------

Merchant information:
Metafizzy
yo@metafizzy.co
http://metafizzy.co


Instructions to merchant:
None provided

----------------------------------------------------------------
Payment details
----------------------------------------------------------------

Description:  Isotope Commercial License,  Item #: 13620, 
Unit price: $25.00 USD
Quantity: 1
Amount: $25.00 USD



Total: $25.00 USD

Receipt No: 2542-5500-0733-6758
Please keep this receipt number for future reference. You'll need it if you contact customer service at Metafizzy or PayPal.

About

An exquisite jQuery plugin for magical layouts that won't crash your browser

Resources

Stars

Watchers

Forks

Packages

No packages published