Bug Tracker

Ticket #1463 (closed bug: fixed)

Opened 2 years ago

Last modified 2 years ago

jQuery slowdowns on consecutive calls

Reported by: offwhite Assigned to: john
Type: bug Priority: critical
Milestone: 1.1.4 Component: event
Version: 1.1.3 Keywords:
Cc: Needs: Review

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.

http://groups.google.com/group/jquery-en/browse_thread/thread/7df49bf044fe13e1/db93b9c35c44d546#db93b9c35c44d546

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

script.js (3.2 kB) - added by offwhite 2 years ago.
The Script
index.html (2.6 kB) - added by offwhite 2 years ago.
The Page
script.2.js (3.9 kB) - added by offwhite 2 years ago.
Revised Script
index.2.html (2.7 kB) - added by offwhite 2 years ago.
Revised Page
jquery-1.1.3.1.adjusted.js (62.2 kB) - added by offwhite 2 years ago.
Adjusted jQuery

Change History

Changed 2 years ago by offwhite

The Script

Changed 2 years ago by offwhite

The Page

Changed 2 years ago by offwhite

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.

Changed 2 years ago by offwhite

Revised Script

Changed 2 years ago by offwhite

Revised Page

Changed 2 years ago by offwhite

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 2 years ago by offwhite

Adjusted jQuery

Changed 2 years ago by john

  • owner deleted
  • component changed from core to event

Changed 2 years ago by john

  • owner set to john

Changed 2 years ago by john

  • status changed from new to closed
  • resolution set to fixed

Fixed in SVN rev [2783].

Changed 2 years ago by john

Oh, and here's the revised test that I ran: http://dev.jquery.com/~john/ticket/ajax/faster.html

Note: See TracTickets for help on using tickets.