Side navigation
#1463 closed bug (fixed)
Opened August 03, 2007 03:20PM UTC
Closed August 19, 2007 11:39PM UTC
Last modified August 20, 2007 12:09AM UTC
jQuery slowdowns on consecutive calls
Reported by: | offwhite | Owned by: | john |
---|---|---|---|
Priority: | critical | Milestone: | 1.1.4 |
Component: | event | Version: | 1.1.3 |
Keywords: | Cc: | ||
Blocked by: | Blocking: |
Description
I put together a test to see how well jQuery would perform when I use it in different ways and discovered that as I repeat the actions in the test it takes longer each time. The test creates a table with 250 cells and then adds a class name, sets a css rule and binds a click event to the span element in each table cell. I time the start and end of the function that does the work with jQuery. For some reason it does additional work on each new call to the function.
I am trying to determine the problem with the profiler in Firebug. That is what is showing me the functions like inArray are being called more times on each consecutive call.
You can see the sample here...
http://brennan.offwhite.net/fasterjquery/
I have also posted to this issue to Google Groups to see if I am somehow not using jQuery right for this test.
This is a critical problem because it will cause the page to start showing the "script is running too long" warning in FF and IE. I am having this problem in a production system.
Attachments (5)
Change History (6)
Changed August 03, 2007 07:17PM UTC by comment:1
Changed August 04, 2007 06:03PM UTC by comment:2
I have resolve the issue. Each time an event is bound to an element the element is stored in an array (this.global[type]). When I bind each of the 250 span elements in the large table it holds onto those 250 event bindings. When I empty and append new markup to rebuild the table the 250 old event bindings become null because they were holding onto the elements which are now gone. Then the new span elements are bound and another 250 items are put into the array. The size of the array continues to grow and it is filled with null values.
My solution was to add a couple of functions to clean the array of null values. Then in the add function that the bind function calls, the cleanEventList function is called whenever the length of the array is over 500. Using that value prevents it from being called each time add is called in my test. Otherwise it needlessly loops over the array over and over. This may not be an ideal solution. The other option is to call $.event.cleanEventList() whenever a large block of markup is removed that may have events bound to them. For a long running web application this function could also be called every few minutes like a garbage collecting thread. I will attach my adjusted version of jQuery.
Remember the function in a global list (for triggering)
if (!this.global[type])
this.global[type] = [];
else if (this.global[type].length > 500)
{
clean the list when it gets big
this.cleanEventList();
}
Changed August 10, 2007 06:27AM UTC by comment:3
component: | core → event |
---|
Changed August 19, 2007 09:50PM UTC by comment:4
owner: | → john |
---|
Changed August 19, 2007 11:39PM UTC by comment:5
resolution: | → fixed |
---|---|
status: | new → closed |
Fixed in SVN rev [2783].
Changed August 20, 2007 12:09AM UTC by comment:6
Oh, and here's the revised test that I ran:
I have found that the bind function is the cause for the additional work with each consecutive call. Leaving it off causes the problem to go away. Instead of using bind I tried the click function but it has the same problem because it simply calls the bind function internally.
I have attempted to wrap the work in the function inside of an anonymous function called with by setTimeout. That helped make the browser a little more responsive but that option is not ideal because the anonymous function can still run for longer than the default 10 seconds that FF allows before prompting the user. With just 1000 nodes this becomes a problem because there is a noticeable delay when binding events to nodes.