I have a trac plugin named DynamicFieldsPlugin. My studies show that this piece of code takes the most time. I know there are a lot of each used here. So I need your advice to improve its performance. Here is my layout.js code: /* * Layout 'class' */ var Layout = function(name){ this.name = name; // Selector for all field tds/ths this.selector = ''; // Return the given field name's td/th element this.get_tx = function(field){} // Return the given td/th element's field name this.get_field = function(tx){} // Move a field's tds and ths to slot i this.move_field = function(field, i){} // Update the field layout given a spec this.update = function(spec){ var this_ = this; // save original field order if (window.dynfields_orig_field_order == undefined) window.dynfields_orig_field_order = Object(); if (window.dynfields_orig_field_order[this.name] == undefined){ window.dynfields_orig_field_order[this.name] = []; jQuery(this.selector).each(function(i,e){ var field = this_.get_field($(this)); if (field) window.dynfields_orig_field_order[this_.name].push(field); }); } // get visible and hidden fields var visible = []; var hidden = []; jQuery.each(window.dynfields_orig_field_order[this.name], function(i,field){ var tx = this_.get_tx(field); if (tx.hasClass('dynfields-hide')){ hidden.push(field); } else { visible.push(field); } }); // get new field order // warning: side-effects! var new_fields = jQuery.merge(visible, hidden); // order the fields this.order_fields(new_fields); } this.order_fields = function(new_fields){ var this_ = this; // determine which fields need to move and move 'em! jQuery(this.selector).each(function(i,e){ var field = this_.get_field($(this)); if (field == ''){ var j = -1; } else { var j = jQuery.inArray(field, new_fields); } // check if field is in the correct slot in the new order if (i != j && i < new_fields.length){ // wrong order! this_.move_field(new_fields[i], i); } }); } }; /* * Inputs Layout implementation */ var inputs_layout = new Layout('inputs'); // selector inputs_layout.selector = '#properties td[class!=fullrow]:parent'; // get_tx inputs_layout.get_tx = function(field){ return jQuery('#field-'+field).parents('td:first'); }; // get_field inputs_layout.get_field = function(td){ var input = td.find(':input:first'); if (!input.length) return ''; return input.attr('id').slice(6); }; // move_field inputs_layout.move_field = function(field, i){ var td = this.get_tx(field); var th = td.parent('tr') .find('th label[for=field-'+field+']') .parent('th'); // find correct row (tr) to insert field var row = Math.round(i/2 - 0.5); // round down row += jQuery('#properties td[class=fullrow]').length; // skip fullrows var tr = jQuery('#properties tr:eq('+row+')'); // find correct column (tx) to insert field var col = 'col'+((i%2)+1); if (tr.find('th').length){ if (col == 'col1'){ var old_th = tr.find('th:first'); if (old_th.get(0) != th.get(0)){ // don't move self to self old_th.before(th); old_th.before(td); } } else { var old_td = tr.find('td:last'); if (old_td.get(0) != td.get(0)){ // don't move self to self old_td.after(td); old_td.after(th); } } } else { // no columns so just insert tr.append(th); tr.append(td); } // let's set col td.removeClass('col1 col2'); th.removeClass('col1 col2'); td.addClass(col); th.addClass(col); }; /* * Header Layout implementation */ var header_layout = new Layout('header'); // selector header_layout.selector = '#ticket .properties th:parent'; // get_tx header_layout.get_tx = function(field){ return jQuery('#h_'+field); }; // get_field header_layout.get_field = function(th){ return th.attr('id').slice(2); }; // move_field header_layout.move_field = function(field, i){ var th = this.get_tx(field); var td = th.parent('tr').find('td[headers=h_'+field+']'); // find correct row (tr) to insert field var row = Math.round(i/2 - 0.5); // round down var tr = jQuery('#ticket .properties tr:eq('+row+')'); // find correct column (tx) to insert field if (tr.find('th').length){ if (i % 2 == 0){ var old_th = tr.find('th:first'); if (old_th.get(0) != th.get(0)){ // don't move self to self old_th.before(th); old_th.before(td); } } else { var old_td = tr.find('td:last'); if (old_td.get(0) != td.get(0)){ // don't move self to self old_td.after(td); old_td.after(th); } } } else { // no columns so just insert tr.append(th); tr.append(td); } }; Code (JavaScript): I will happily give more information about this issue. Please help.
The .each() is being used only three times in your code so there are not "a lot of" .each() used here. According the responses made in the following stackoverflow thread, the difference between .each() and for() loop is noticeable only when the iteration is tens of thousand times. If the iteration of your .each() do not need to be performed tens of thousand times, I would say it's not a problem. http://stackoverflow.com/questions/11887450/each-vs-for-loop-and-performance One way to improve the speed is always performing trivial calculations outside of .each(). For example, rather than writing code like if (i < $('div').length) { ...... } inside of .each(), do var divLength = $('div').length; outside of .each() and write the code inside of .each() as if (i < divLength) { ...... }.