Skip to main content

Search and Top Navigation

#6754 closed bug (duplicate)

Opened December 16, 2010 10:43AM UTC

Closed December 16, 2010 12:55PM UTC

Last modified December 16, 2010 12:55PM UTC

Autocomplete performs extremely slow on local arrays exceeding 200 items on IE Browser (6, 7)

Reported by: asutor Owned by:
Priority: minor Milestone: 1.9.0
Component: ui.autocomplete Version: 1.8.7
Keywords: Cc:
Blocked by: Blocking:
Description

Performance Analysis on Autocomplete

Current Situation

Having a local array > 200 items the performance of the display of the whole suggestion list is extremely slow under the IE.

elem.autocomplete( "search", "" );

Please refer to the following table to see the performance results.

''Hints:''

  • the performance measurement was only investigating the execution of the ''_suggest'' function.
  • IE 7.0.5730 and FF 3.6.10 were tested natively
  • for IE 6 and 7 the IE Tester was used (| IETester Homepage)
  • the duration is given in ms
  • the timeout on IE for JS execution is set to 10 seconds

||= =||= FF (3.6.10) =||==||= IE (7.0.5730) =||==||= IE 6 (IETester) =||==||= IE 7 (IETester) =||==||

||= No. of items =||= page reload =||= without reload =||= page reload =||= without reload =||= page reload =||= without reload =||= page reload =||= without reload =||

|| 10 || 19 || 25 || 31 || 47 || 31 || 47 || 47 || 62 ||

|| 50 || 71 || 110 || 187 || 313 || 187 || 297 || 204 || 313 ||

|| 100 || 139 || 210 || 484 || 735 || 469 || 703 || 484 || 718 ||

|| 200 || 279 || 404 || 1359 || 1859 || 1344 || 1891 || 1375 || 1922 ||

|| 400 || 554 || 868 || 4531 || 5531 || 4624 || 5984 || 4656 || 5562 ||

|| 800 || 1107 || 1656 || >10000 || >10000 || >10000 || >10000 || >10000 || >10000 ||

Solution and Hints

Checking the execution duration for ''_suggest'' I discovered that the code line

this.menu.refresh();

is taking the most time. The reason for this is the usage of the time consuming method ''children(a)'' within this method. There are other places within that code which using additional slow functions, but this part is the worst.

Current Implementation of refresh()

	refresh: function() {
		var self = this;

		// don't refresh list items that are already adapted
		var items = this.element.children("li:not(.ui-menu-item):has(a)")
			.addClass("ui-menu-item")
			.attr("role", "menuitem");
		
		items.children("a")
			.addClass("ui-corner-all")
			.attr("tabindex", -1)
			// mouseenter doesn't work with event delegation
			.mouseenter(function( event ) {
				self.activate( event, $(this).parent() );
			})
			.mouseleave(function() {
				self.deactivate();
			});
	},

A more quicker implementation of refresh()

	refresh: function() {
		var self = this;
		// don't refresh list items that are already adapted
		var items = this.element.children("li:not(.ui-menu-item):has(a)")
			.addClass("ui-menu-item")
			.attr("role", "menuitem");
		items.each(function() {
			var item = $(this).children();
			item.addClass("ui-corner-all");
			item.attr("tabindex", -1);
			item.attr("tabindex", -1);
			item.mouseenter(function( event ) {
				self.activate( event, $(this).parent() );
			});
			item.mouseleave(function() {
				self.deactivate();
			});
		}); 
	},

Probably there is a much better solution for it but this part did help a lot (speeded up 4 times). The average display time for 400 items were under 1 s. In general using the DOM manipulation should be limited and replacing the HTML parts in whole is much quicker.

I used the following article about | JQuery performance in order to find a better solution for the current problem.

Attachments (0)
Change History (4)

Changed December 16, 2010 11:00AM UTC by jzaefferer comment:1

description: \ == Performance Analysis on Autocomplete == \ \ '''Current Situation''' \ \ Having a local array > 200 items the performance of the display of the whole suggestion list is extremely slow under the IE. \ \ {{{ \ elem.autocomplete( "search", "" ); \ }}} \ \ Please refer to the following table to see the performance results. \ \ ''Hints:'' \ * the performance measurement was only investigating the execution of the ''_suggest'' function. \ * IE 7.0.5730 and FF 3.6.10 were tested natively \ * for IE 6 and 7 the IE Tester was used ([http://www.my-debugbar.com/wiki/IETester/HomePage | IETester Homepage]) \ * the duration is given in ms \ * the timeout on IE for JS execution is set to 10 seconds \ \ ||= =||= FF (3.6.10) =||==||= IE (7.0.5730) =||==||= IE 6 (IETester) =||==||= IE 7 (IETester) =||==|| \ ||= No. of items =||= page reload =||= without reload =||= page reload =||= without reload =||= page reload =||= without reload =||= page reload =||= without reload =|| \ || 10 || 19 || 25 || 31 || 47 || 31 || 47 || 47 || 62 || \ || 50 || 71 || 110 || 187 || 313 || 187 || 297 || 204 || 313 || \ || 100 || 139 || 210 || 484 || 735 || 469 || 703 || 484 || 718 || \ || 200 || 279 || 404 || 1359 || 1859 || 1344 || 1891 || 1375 || 1922 || \ || 400 || 554 || 868 || 4531 || 5531 || 4624 || 5984 || 4656 || 5562 || \ || 800 || 1107 || 1656 || >10000 || >10000 || >10000 || >10000 || >10000 || >10000 || \ \ '''Solution and Hints''' \ \ Checking the execution duration for ''_suggest'' I discovered that the code line \ \ {{{ \ this.menu.refresh(); \ }}} \ \ is taking the most time. The reason for this is the usage of the time consuming method ''children(a)'' within this method. There are other places within that code which using additional slow functions, but this part is the worst. \ \ '''Current Implementation of refresh()''' \ \ {{{ \ refresh: function() { \ var self = this; \ \ // don't refresh list items that are already adapted \ var items = this.element.children("li:not(.ui-menu-item):has(a)") \ .addClass("ui-menu-item") \ .attr("role", "menuitem"); \ \ items.children("a") \ .addClass("ui-corner-all") \ .attr("tabindex", -1) \ // mouseenter doesn't work with event delegation \ .mouseenter(function( event ) { \ self.activate( event, $(this).parent() ); \ }) \ .mouseleave(function() { \ self.deactivate(); \ }); \ }, \ }}} \ \ '''A more quicker implementation of refresh()''' \ \ {{{ \ refresh: function() { \ var self = this; \ // don't refresh list items that are already adapted \ var items = this.element.children("li:not(.ui-menu-item):has(a)") \ .addClass("ui-menu-item") \ .attr("role", "menuitem"); \ items.each(function() { \ var item = $(this).children(); \ item.addClass("ui-corner-all"); \ item.attr("tabindex", -1); \ item.attr("tabindex", -1); \ item.mouseenter(function( event ) { \ self.activate( event, $(this).parent() ); \ }); \ item.mouseleave(function() { \ self.deactivate(); \ }); \ }); \ }, \ \ }}} \ \ Probably there is a much better solution for it but this part did help a lot (speeded up 4 times). The average display time for 400 items were under 1 s. In general using the DOM manipulation should be limited and replacing the HTML parts in whole is much quicker. \ \ I used the following article about [http://www.artzstudio.com/2009/04/jquery-performance-rules/ | JQuery performance] in order to find a better solution for the current problem.== Performance Analysis on Autocomplete == \ \ '''Current Situation''' \ \ Having a local array > 200 items the performance of the display of the whole suggestion list is extremely slow under the IE. \ \ {{{ \ elem.autocomplete( "search", "" ); \ }}} \ \ Please refer to the following table to see the performance results. \ \ ''Hints:'' \ * the performance measurement was only investigating the execution of the ''_suggest'' function. \ * IE 7.0.5730 and FF 3.6.10 were tested natively \ * for IE 6 and 7 the IE Tester was used ([http://www.my-debugbar.com/wiki/IETester/HomePage | IETester Homepage]) \ * the duration is given in ms \ * the timeout on IE for JS execution is set to 10 seconds \ \ ||= =||= FF (3.6.10) =||==||= IE (7.0.5730) =||==||= IE 6 (IETester) =||==||= IE 7 (IETester) =||==|| \ ||= No. of items =||= page reload =||= without reload =||= page reload =||= without reload =||= page reload =||= without reload =||= page reload =||= without reload =|| \ || 10 || 19 || 25 || 31 || 47 || 31 || 47 || 47 || 62 || \ || 50 || 71 || 110 || 187 || 313 || 187 || 297 || 204 || 313 || \ || 100 || 139 || 210 || 484 || 735 || 469 || 703 || 484 || 718 || \ || 200 || 279 || 404 || 1359 || 1859 || 1344 || 1891 || 1375 || 1922 || \ || 400 || 554 || 868 || 4531 || 5531 || 4624 || 5984 || 4656 || 5562 || \ || 800 || 1107 || 1656 || >10000 || >10000 || >10000 || >10000 || >10000 || >10000 || \ \ '''Solution and Hints''' \ \ Checking the execution duration for ''_suggest'' I discovered that the code line \ \ {{{ \ this.menu.refresh(); \ }}} \ \ is taking the most time. The reason for this is the usage of the time consuming method ''children(a)'' within this method. There are other places within that code which using additional slow functions, but this part is the worst. \ \ '''Current Implementation of refresh()''' \ \ {{{ \ refresh: function() { \ var self = this; \ \ // don't refresh list items that are already adapted \ var items = this.element.children("li:not(.ui-menu-item):has(a)") \ .addClass("ui-menu-item") \ .attr("role", "menuitem"); \ \ items.children("a") \ .addClass("ui-corner-all") \ .attr("tabindex", -1) \ // mouseenter doesn't work with event delegation \ .mouseenter(function( event ) { \ self.activate( event, $(this).parent() ); \ }) \ .mouseleave(function() { \ self.deactivate(); \ }); \ }, \ }}} \ \ '''A more quicker implementation of refresh()''' \ \ {{{ \ refresh: function() { \ var self = this; \ // don't refresh list items that are already adapted \ var items = this.element.children("li:not(.ui-menu-item):has(a)") \ .addClass("ui-menu-item") \ .attr("role", "menuitem"); \ items.each(function() { \ var item = $(this).children(); \ item.addClass("ui-corner-all"); \ item.attr("tabindex", -1); \ item.attr("tabindex", -1); \ item.mouseenter(function( event ) { \ self.activate( event, $(this).parent() ); \ }); \ item.mouseleave(function() { \ self.deactivate(); \ }); \ }); \ }, \ \ }}} \ \ Probably there is a much better solution for it but this part did help a lot (speeded up 4 times). The average display time for 400 items were under 1 s. In general using the DOM manipulation should be limited and replacing the HTML parts in whole is much quicker. \ \ I used the following article about [http://www.artzstudio.com/2009/04/jquery-performance-rules/ | JQuery performance] in order to find a better solution for the current problem.

So the main change you did was removing the selector from the .children() call. As we already filter with :has(a), that change makes sense and shouldn't make any sementic difference.

Could you verify that removing the selector "a" from the original code makes a noticeable difference?

Changed December 16, 2010 11:01AM UTC by jzaefferer comment:2

status: newopen

Changed December 16, 2010 12:55PM UTC by scottgonzalez comment:3

resolution: → duplicate
status: openclosed

Thanks for the performance analysis. I had already tracked this down and came up with the same fix a few days ago. There should really be a fix in jQuery core for methods that are guaranteed not to produce duplicate items (the duplication checks are what take all the time).

Changed December 16, 2010 12:55PM UTC by scottgonzalez comment:4

Duplicate of #6670.