views:

83

answers:

2

I have a jsp which uses a lot of javascript and it's just not fast enough. I would like to optimize it so first, here's a part of the code:

In the jsp I have the initialization:

window.onload = function () {
        formCollection.pageSize.value = "<%= pagingSize%>";
        elemCollection = iDom3.Table.all["spis"].XML.DOM;
        <%  if (resultList != null) { %>
        elementsNumber = <%= resultList.size() %>;
        <%} else { %>
        elementsNumber = 0;
        <% } %> 
        contextPath = "<%= request.getContextPath() %>";
    }

In my js file I have two types of js functions:

// gets the first element and sets it's value to all the other; 
//the selectSingleNode function is used because I use XSLT transformation 
//to generate the table

_setTehJed = function(){    
        var resultId = formCollection.elements["idTehJedinice_spis_1"].value;
        var resultText = formCollection.elements["tehnicka_spis_1"].value;
        if (resultId != ""){
            var counter = 1;
            while (counter<elementsNumber){
                counter++;
                if(formCollection.elements["idTehJedinice_spis_"+counter] != null){
                    formCollection.elements["idTehJedinice_spis_"+counter].value=resultId;
                    formCollection.elements["tehnicka_spis_"+counter].value=resultText;
                }
                var node=elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_"+counter+"']/data[@col = 'tehnicka']/title");
                node.text=resultText;
                var node2=elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_"+counter+"']/data[@col = 'idTehJedinice']/title");
                node2.text=resultId;
            }
        }

    }

// sets the elements checkbox to checked or unchecked
_SelectCheckRokCuvanja = {
        all : [],

        Item : function (oItem, sId) {
                this.all["spis_"+sId] = oItem.value;
                if (oItem.checked) {
                    elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_"+sId+"']/data[@col = 'rokCheck']").setAttribute("default", "true");
                }else{
                    elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_"+sId+"']/data[@col = 'rokCheck']").setAttribute("default", "false");
                }
        }
    }

I've used these tips:

http://blogs.msdn.com/b/ie/archive/2006/08/28/728654.aspx http://code.google.com/speed/articles/optimizing-javascript.html

but I still think something could be done like defining the functions like this:

In the jsp:

window.onload = function () {
        iDom3.DigitalnaArhivaPrihvat.formCollection=document.forms["controller"];
        iDom3.DigitalnaArhivaPrihvat.formCollection.pageSize.value = "<%= pagingSize%>";
        iDom3.DigitalnaArhivaPrihvat.elemCollection = iDom3.Table.all["spis"].XML.DOM;
        <%  if (resultList != null) { %>
        iDom3.DigitalnaArhivaPrihvat.elementsNumber = <%= resultList.size() %>
        <%} else { %>
        iDom3.DigitalnaArhivaPrihvat.elementsNumber = 0;
        <% } %> 

}

in the js:

iDom3.DigitalnaArhivaPrihvat = {

    formCollection:null,
    elemCollection:null,
    elementsNumber:null,


_setTehJed : function(){    
        var resultId = this.formCollection.elements.idTehJedinice_spis_1.value;
        var resultText = this.formCollection.elements.tehnicka_spis_1.value;
        if (resultId != ""){
            var counter = 1;
            while (counter<this.elementsNumber){
                counter++;
                if(this.formCollection.elements["idTehJedinice_spis_"+counter] !== null){
                    this.formCollection.elements["idTehJedinice_spis_"+counter].value=resultId;
                    this.formCollection.elements["tehnicka_spis_"+counter].value=resultText;
                }
                var node=this.elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_"+counter+"']/data[@col = 'tehnicka']/title");
                node.text=resultText;
                var node2=this.elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_"+counter+"']/data[@col = 'idTehJedinice']/title");
                node2.text=resultId;
            }
        }

    },

_SelectCheckRokCuvanja = {
        all : [],

        Item : function (oItem, sId) {
                this.all["spis_"+sId] = oItem.value;
                if (oItem.checked) {
                    this.elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_"+sId+"']/data[@col = 'rokCheck']").setAttribute("default", "true");
                }else{
                    this.elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_"+sId+"']/data[@col = 'rokCheck']").setAttribute("default", "false");
                }
        }
    }

but the problem is scoping (if I do it like this, the second function does not execute properly). Any suggestions?

Edit: Data structure of the table:

<row id="spis_3">
    <data col="rokCheck" type="check" default="false" onchange="_ChangeTypeRokCuvanje(this,'3')" >
    <title>false</title>
    <description>Tehnička jedinica</description>
</data>
+1  A: 

Just replace the reference to this with _SelectCheckRokCuvanja

_SelectCheckRokCuvanja = {
    all: [],
    Item: function (oItem, sId) {
        _SelectCheckRokCuvanja.all["spis_" + sId] = oItem.value;
        if (oItem.checked) {
            _SelectCheckRokCuvanja.elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_" + sId + "']/data[@col = 'rokCheck']").setAttribute("default", "true");
        } else {
            _SelectCheckRokCuvanja.elemCollection.selectSingleNode("/suite/table/rows/row[@id = 'spis_" + sId + "']/data[@col = 'rokCheck']").setAttribute("default", "false");
        }
    }
}
Sean Kinsey
+3  A: 

selectSingleNode() is a pretty expensive operation. You should try to avoid it. There are two solutions:

  1. Iterate over the data structure yourself (so you don't have to search the DOM for the table but you can directly modify row by row).

  2. Since you assign every row an ID, you should be able to use document.getElementById() without the expensive XPath lookup.

  3. Use a framework like jquery to get all relevant nodes at once (-> only 1 expensive lookup) and then iterate over the list.

[EDIT] See Traversing an HTML table with JavaScript and DOM Interfaces for an example how to implement #1.

Aaron Digulla
I'm not sure I could use getElementById(), including jquery just for one feature seems expensive, so how could I implement solution 1? I've edited in a part of the data structure in the XSLT table
Andrija
See this document how to walk the DOM tree: https://developer.mozilla.org/en/Traversing_an_HTML_table_with_JavaScript_and_DOM_Interfaces
Aaron Digulla