[jQuery] For Loops vs Each Loops while optimizing efficiency
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);
- }
- };
I will happily give more information about this issue. Please help.