Skip to main content

Search and Top Navigation

#15043 closed bug (fixed)

Opened September 08, 2016 12:39PM UTC

Closed September 13, 2016 07:16PM UTC

Last modified September 13, 2016 07:46PM UTC

Widget: Internal list of elements with classes can't be cleaned up

Reported by: WickedDevils Owned by: arschmitz
Priority: minor Milestone: 1.12.1
Component: ui.widget Version: 1.12.0
Keywords: Cc:
Blocked by: Blocking:
Description

I used the code from site http://jqueryui.com/autocomplete/#combobox and noticed a significant performance issue on my page. My list has ~3000 options in the combobox. I noticed that most of the time it was stuck in the in the jquery js file within this set of code:

	indexOf = function( list, elem ) {
		var i = 0,
			len = list.length;
		for ( ; i < len; i++ ) {
			if ( list[i] === elem ) {
				return i;
			}
		}
		return -1;
	},`

Even though my list object was only expected to be ~3000 rows, it was actually significantly higher. Here is my stacktrace:

indexOf (jquery-1.12.4.js:644)
hasDuplicate (jquery-1.12.4.js:1375)
Sizzle.uniqueSort (jquery-1.12.4.js:1518)
processClassString (jquery-ui.js:510)
_classes (jquery-ui.js:523)
_toggleClass (jquery-ui.js:549)
_addClass (jquery-ui.js:537)
refresh (jquery-ui.js:5249)
(anonymous function) (jquery-ui.js:144)
_suggest (jquery-ui.js:6100)
(anonymous function) (jquery-ui.js:144)
__response (jquery-ui.js:6043)
(anonymous function) (jquery-ui.js:144)
_superApply (jquery-ui.js:133)
__response (jquery-ui.js:6229)
(anonymous function) (jquery-ui.js:144)
(anonymous function) (jquery-ui.js:6027)
proxy (jquery-1.12.4.js:529)
_source (combobox.html:108)
(anonymous function) (jquery-ui.js:144)
proxy (jquery-1.12.4.js:529)
_search (jquery-ui.js:6019)
(anonymous function) (jquery-ui.js:144)
search (jquery-ui.js:6011)
(anonymous function) (jquery-ui.js:144)
(anonymous function) (jquery-ui.js:5992)
handlerProxy (jquery-ui.js:621)

In processClassString it does line:

current = $( $.unique( current.get().concat( options.element.get() ) ) );

The current list is my 3000 or so rows initially, and then it adds the elements back into that list making it roughly 6000 rows. Depending on how the user is interacting with the page (clicking the dropdown icon multiple times, typing into the textbox for the filter and then deleting the text, etc), it will keep adding to itself. At one point I had almost 200,000 rows in my 'list' variable.

I was able to reproduce this by stepping through the code using Chrome developer tools on http://jqueryui.com/autocomplete/#combobox .

Attachments (0)
Change History (11)

Changed September 08, 2016 12:45PM UTC by scottgonzalez comment:1

resolution: → patcheswelcome
status: newclosed

From the demo page: "This is not a supported or even complete widget."

Changed September 08, 2016 01:32PM UTC by WickedDevils comment:2

It's not the widget that is the problem. It is the code behind it that duplicates the data. Did you read what I said at all?

Changed September 08, 2016 02:32PM UTC by scottgonzalez comment:3

Yes, I read what you wrote. I don't see how the code could get up to 200,000 elements from 3,000. It does one concatenation, and then removes the duplicates, so the max count should never be more than 6,000. But even that number should never be reached. Because you've said that there are many interactions involved, and each interaction is actually its own completely separate operation with a new list each time, I don't see the correlation. Your stack trace shows processClassString() being called once and that doesn't provide any information about the number of elements.

Unless you can provide a concrete way for us to see that there is a problem, there's not much we can do.

Changed September 08, 2016 04:17PM UTC by WickedDevils comment:4

I created a video on how to reproduce the issue with the jquery autocomplete example. I have significantly more import options than what the example has.

https://www.youtube.com/watch?v=9zNP5DsyKqA

Changed September 08, 2016 04:29PM UTC by WickedDevils comment:5

This is the chunk of code I have found so far where the ui-menu-items are added


		// Don't refresh list items that are already adapted
		newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
		newWrappers = newItems.children()
			.not( ".ui-menu" )
				.uniqueId()
				.attr( {
					tabIndex: -1,
					role: this._itemRole()
				} );
		this._addClass( newItems, "ui-menu-item" )
			._addClass( newWrappers, "ui-menu-item-wrapper" );

I can see them adding to the list in newItems

Changed September 08, 2016 04:32PM UTC by scottgonzalez comment:6

component: ui.autocompleteui.widget
resolution: patcheswelcome
status: closedreopened
summary: JQuery autocomplete performance issueWidget: Internal list of elements with classes can't be cleaned up
version: 1.11.31.12.0

Ok, now I see what's happening. The widget keeps track of the element that have classes applied, but in the case of autocomplete, the menu is constantly rebuilt, so the list grows with every render. Widgets need a way to signify that elements have been removed and should be taken out of the list.

Changed September 08, 2016 08:24PM UTC by WickedDevils comment:7

I reverted jquery UI JS to 1.9 and this problem does not exist. Somewhere between 1.9 and 1.12 it is not working correctly.

Changed September 08, 2016 08:29PM UTC by scottgonzalez comment:8

That somewhere is 1.12.0, which is why I corrected the version field.

Changed September 13, 2016 07:16PM UTC by rjollos comment:9

_comment0: Fixed in [https://github.com/jquery/jquery-ui/commit/89af4c292eaa5fc1c83437ca71085264dcbef34a 89af4c292eaa5fc1c83437ca71085264dcbef34a]1473795928474446
milestone: none1.12.1
resolution: → fixed
status: reopenedclosed

Changed September 13, 2016 07:45PM UTC by arschmitz comment:10

owner: → arschmitz

In [changeset:"89af4c292eaa5fc1c83437ca71085264dcbef34a" 89af4c2]:

#!CommitTicketReference repository="" revision="89af4c292eaa5fc1c83437ca71085264dcbef34a"
Widget: Untrack classes elements when they are removed from the DOM

Fixes #15043
Closes gh-1744

Changed September 13, 2016 07:46PM UTC by rjollos comment:11

description: I used the code from site http://jqueryui.com/autocomplete/#combobox and noticed a significant performance issue on my page. My list has ~3000 options in the combobox. I noticed that most of the time it was stuck in the in the jquery js file within this set of code: \ \ ` indexOf = function( list, elem ) { \ var i = 0, \ len = list.length; \ for ( ; i < len; i++ ) { \ if ( list[i] === elem ) { \ return i; \ } \ } \ return -1; \ },` \ \ Even though my list object was only expected to be ~3000 rows, it was actually significantly higher. Here is my stacktrace: \ \ `indexOf (jquery-1.12.4.js:644) \ hasDuplicate (jquery-1.12.4.js:1375) \ Sizzle.uniqueSort (jquery-1.12.4.js:1518) \ processClassString (jquery-ui.js:510) \ _classes (jquery-ui.js:523) \ _toggleClass (jquery-ui.js:549) \ _addClass (jquery-ui.js:537) \ refresh (jquery-ui.js:5249) \ (anonymous function) (jquery-ui.js:144) \ _suggest (jquery-ui.js:6100) \ (anonymous function) (jquery-ui.js:144) \ __response (jquery-ui.js:6043) \ (anonymous function) (jquery-ui.js:144) \ _superApply (jquery-ui.js:133) \ __response (jquery-ui.js:6229) \ (anonymous function) (jquery-ui.js:144) \ (anonymous function) (jquery-ui.js:6027) \ proxy (jquery-1.12.4.js:529) \ _source (combobox.html:108) \ (anonymous function) (jquery-ui.js:144) \ proxy (jquery-1.12.4.js:529) \ _search (jquery-ui.js:6019) \ (anonymous function) (jquery-ui.js:144) \ search (jquery-ui.js:6011) \ (anonymous function) (jquery-ui.js:144) \ (anonymous function) (jquery-ui.js:5992) \ handlerProxy (jquery-ui.js:621) \ ` \ \ In processClassString it does line: \ \ `current = $( $.unique( current.get().concat( options.element.get() ) ) );` \ \ The current list is my 3000 or so rows initially, and then it adds the elements back into that list making it roughly 6000 rows. Depending on how the user is interacting with the page (clicking the dropdown icon multiple times, typing into the textbox for the filter and then deleting the text, etc), it will keep adding to itself. At one point I had almost 200,000 rows in my 'list' variable. \ \ I was able to reproduce this by stepping through the code using Chrome developer tools on http://jqueryui.com/autocomplete/#combobox . I used the code from site http://jqueryui.com/autocomplete/#combobox and noticed a significant performance issue on my page. My list has ~3000 options in the combobox. I noticed that most of the time it was stuck in the in the jquery js file within this set of code: \ {{{#!js \ indexOf = function( list, elem ) { \ var i = 0, \ len = list.length; \ for ( ; i < len; i++ ) { \ if ( list[i] === elem ) { \ return i; \ } \ } \ return -1; \ },` \ }}} \ Even though my list object was only expected to be ~3000 rows, it was actually significantly higher. Here is my stacktrace: \ \ {{{ \ indexOf (jquery-1.12.4.js:644) \ hasDuplicate (jquery-1.12.4.js:1375) \ Sizzle.uniqueSort (jquery-1.12.4.js:1518) \ processClassString (jquery-ui.js:510) \ _classes (jquery-ui.js:523) \ _toggleClass (jquery-ui.js:549) \ _addClass (jquery-ui.js:537) \ refresh (jquery-ui.js:5249) \ (anonymous function) (jquery-ui.js:144) \ _suggest (jquery-ui.js:6100) \ (anonymous function) (jquery-ui.js:144) \ __response (jquery-ui.js:6043) \ (anonymous function) (jquery-ui.js:144) \ _superApply (jquery-ui.js:133) \ __response (jquery-ui.js:6229) \ (anonymous function) (jquery-ui.js:144) \ (anonymous function) (jquery-ui.js:6027) \ proxy (jquery-1.12.4.js:529) \ _source (combobox.html:108) \ (anonymous function) (jquery-ui.js:144) \ proxy (jquery-1.12.4.js:529) \ _search (jquery-ui.js:6019) \ (anonymous function) (jquery-ui.js:144) \ search (jquery-ui.js:6011) \ (anonymous function) (jquery-ui.js:144) \ (anonymous function) (jquery-ui.js:5992) \ handlerProxy (jquery-ui.js:621) \ }}} \ \ In processClassString it does line: \ \ `current = $( $.unique( current.get().concat( options.element.get() ) ) );` \ \ The current list is my 3000 or so rows initially, and then it adds the elements back into that list making it roughly 6000 rows. Depending on how the user is interacting with the page (clicking the dropdown icon multiple times, typing into the textbox for the filter and then deleting the text, etc), it will keep adding to itself. At one point I had almost 200,000 rows in my 'list' variable. \ \ I was able to reproduce this by stepping through the code using Chrome developer tools on http://jqueryui.com/autocomplete/#combobox .