Quantcast
Channel: Devon Govett » jQuery
Viewing all articles
Browse latest Browse all 2

How To Make jQuery.empty Over 10x Faster

$
0
0

jQuery has a function called empty, which removes all child elements from a given element. Internally, empty is used in the html function, and many other places. Speed is an important thing to web application developers which I have blogged about in the past. In my case, I was writing a highly dynamic app with jQuery, and the empty function was a performance bottleneck for me since the element I was emptying often contained over 500 children.

The implementation of jQuery’s empty function is fairly simple: iterate through all of the elements children and remove them one by one. As I have written about before, every time you modify the DOM so that the layout changes, the browser must reflow and repaint. Thus when jQuery iterates over all of the child nodes removing them one by one, the browser must reflow after each removal. This can be slow if you are dealing with a lot of elements.

How can we make this faster?

I initially thought that it would be faster to set the element’s innerHTML property to “” than to iterate, and I was right in most circumstances. Unfortunately, there are problems using innerHTML such as it being impossible to set the innerHTML of a table row in IE, which jQuery solves in the jQuery.html function. Using jQuery.html(“”) turned out to be faster than jQuery.empty() in all browsers except Firefox.

After a little digging, and a lot of performance testing, I had a method that was much faster than jQuery.empty() – in some cases up to 10x the speed. Here is the method:

jQuery.fn.removeAll = function() {
	this.each(function() {
		var newEl = this.cloneNode(false);
		this.parentNode.replaceChild(newEl, this);
		
		//Copy back events if they haven't been copied already by IE
		if(jQuery.support.noCloneEvent) {
			cloneCopyEvent($(this), $(newEl));
		}
	});
};

This function loops through all of the selected jQuery objects, and removes the children from all of them. Rather than iterating over all of the children in order to remove them, we simply clone the parent with deep clone set to false. This means that the parent element will be cloned but not the child elements. Once we have this clone in memory, we simply replace the existing element with the new element thereby removing all of the children. Unfortunately, in W3C compliant browsers cloneNode does not clone events attached to the original element along with the element itself, so we have to copy them back over. IE copies them over with cloneNode automatically, and luckily jQuery has a flag that lets us no whether the elements haven’t been copied over, in the form of jQuery.support.noCloneEvent. I’m using the internal jQuery function cloneCopyEvent to copy the events over.

The Benchmarks

I created several charts detailing the performance increases in various browsers. All of the tests were done on the same machine with the latest versions of each of the 4 major browsers and the latest beta of jQuery 1.4. As an interesting side note, IE and Firefox are far faster than the Webkit based browsers Chrome and Safari at removing elements from the DOM. This is interesting because both of those browsers are known for their speed. Here are the charts. I’ve created an overview chart and a breakdown by browser. Click to download a PDF.

Summary: This implementation of jQuery.empty can be over 10 times faster than the version included with jQuery beta 1.4.

I will be submitting this as a patch to the jQuery team, so you may see this code in jQuery sometime in the future!




Viewing all articles
Browse latest Browse all 2

Trending Articles