Decomposing and tuning a slow performing component load
User complains that their component loading function performs poorly. Following is the code fragment used when a tab containing grid data is shown.
function loadMyUniverseData(){
tabActiveNow = "myUniverseAreas";
changeCustomize(); // To change the customize button properties - located in same file
changeCreateBusareaButton(); // To change the create universe areas button properties
var universeAreasObj = CAD.getJSXByName("universeAreas");
var myUniverseAreasObj = CAD.getJSXByName("myUniverseBlock");
var commonBlockObj = CAD.getJSXByName("universeBlockChild");
var doneObj = myUniverseAreasObj.adoptChild(commonBlockObj);
CAD.getJSXByName("myUniverseBlock").repaint();
//CAD.getJSXByName("universeAreas").repaint();
var topic = "DreamData";
var recordCount = 0;
var responseXML = "";
sqlStatement = CAD.getCache()getDocument('myUniverseData_xml' );
recordCount = sqlStatement.selectNodes("//record").getLength();
if(recordCount <= 0) {
var query = "http://mystage.example.com/AUD/giAuditDB/getDataFromRPTServlet?frmWhere=MyUniverse"
var objRequest = new jsx3.net.Request();
objRequest.open('GET',query);
objRequest.send();
responseXML = objRequest.getResponseText();
} else {
responseXML = sqlStatement;
}
var objResponseXMLBusArea = new jsx3.xml.Document();
objResponseXMLBusArea.loadXML(responseXML);
var objRecord = CAD.getCache()setDocument('myUniverseData.xml', objResponseXMLBusArea );
objRecord = CAD.getCache()setDocument('myUniverseData_xml', objResponseXMLBusArea );
var objRecord = CAD.getCache()setDocument('commonUniverseData.xml', objResponseXMLBusArea );
objRecord = CAD.getCache()setDocument('commonUniverseData_xml', objResponseXMLBusArea );
recordCount = 0;
recordCount = CAD.getCache()getDocument('commonUniverseData_xml').selectNodes("//record").getLength();
CAD.getJSXByName("blkMessage").setText(recordCount + " records in set. ").repaint();
CAD.getJSXByName("grid" + topic).repaint();
CAD.getJSXByName("SearchFilter").repaint();
}
Analysis and Suggestions
There are several reasons why switching tabs is taking so long in this code
1. Uneccessary repaint
First, when you adopt a control from one parent to another, there is no need to call repaint. This is handled automatically for you by the system. Any call to repaint, therefore, would be inefficient.
2. Blocking javascript
Next, it is important to note that the user's perception of performance is often tantamount to the actual performance. In my case, I took your existing function...and modified it by splitting it up into three separate functions:
// this function is called when clicked on "My Universe Areas" tab function loadMyUniverseData(){ window.setTimeout(function() { loadMyUniverseDataDelay1(); },0); } function loadMyUniverseDataDelay1() { // To change the customize button properties - located in same file changeCreateBusareaButton(); changeCustomize(); // To change the create universe areas button properties var myUniverseAreasObj = CAD.getJSXByName("myUniverseBlock"); var commonBlockObj = CAD.getJSXByName("universeBlockChild"); var doneObj = myUniverseAreasObj.adoptChild(commonBlockObj); window.setTimeout(function() { loadMyUniverseDataDelay2(); },0); } function loadMyUniverseDataDelay2() { var recordCount = 0; var responseXML; var sqlStatement = CAD.getCache()getDocument('myUniverseData_xml' ); recordCount = sqlStatement.selectNodes("//record").getLength(); if(recordCount <= 0) { var query = "http://mystage.example.com/AUD/giAuditDB/getDataFromRPTServlet?frmWhere=MyUniverse" var objRequest = new jsx3.net.Request(); objRequest.open('GET',query); objRequest.send(); responseXML = objRequest.getResponseText(); } else { responseXML = sqlStatement; } var objResponseXMLBusArea = new jsx3.Document(); objResponseXMLBusArea.load(responseXML); CAD.getCache().setDocument('myUniverseData_xml', objResponseXMLBusArea ); CAD.getCache().setDocument('commonUniverseData_xml', objResponseXMLBusArea ); recordCount = objResponseXMLBusArea.selectNodes("//record").getLength(); CAD.getJSXByName("blkMessage").setText(recordCount + " records in set. ",true); CAD.getJSXByName("grid" + topic).repaint(); CAD.getJSXByName("SearchFilter").repaint(); }
Please note that I also removed the unnecessary repaints and duplicate statements in your original function, but the code flows essentially the same, just spread out across three functions.
3. Avoid Synchronous Request
- 3. Synchronous request - Finally, make sure that when you query for your data that that you do so asynchronously. In your case I see that the call is synchronous:
var objRequest = new jsx3.net.Request(); objRequest.open('GET', query); objRequest.send();
Because your call is synchronous, if there is any delay in the server's response, the entire browser will "lock-up" until the server responds. In a situation like this, what looks like a slow repaint on the front-end is actually a delay in the server's response. If the server takes 5 seconds to respond, you've just added five seconds to the amount of time it takes to switch from one tab to another, effectively confusing the user who will then click the tab multiple times, wondering why the tab won't change.
Here is a sample for how to create an asynchronous call.
Note that I have a handler function (myHandler) that is subscribed to the asynchronous event:
window.myHandler = function(objEvent) {
//get a handle to the http control -- it's the 'target' for this event
var objHttp = objEvent.target;
jsx3.log(objHttp.getResponseText());
// create new document using response text
sqlStatement = new jsx3.xml.Document().loadXML(objHttp.getResponseText();
}
var objHttp = new jsx3.net.Request();
objHttp.open("GET", query, true);
objHttp.subscribe(jsx3.net.Request.EVENT_ON_RESPONSE, myHandler);
objHttp.send();
4. Further optimizations
- a) For loading XML you could even use the Cache.getOrOpenAsync() method.
- b) Reduce the number of calls to set and get XML document
- c) Use XML Bind property to auto-repaint when new document is set to the jsx3.app.Cache.
- d) For Matrix, 1) use repaintData() 2) don't manually repaint at all, use XML Bind.
function loadMyUniverseDataDelay2() {
var query = "http://mystage.example.com/AUD/giAuditDB/getDataFromRPTServlet?frmWhere=MyUniverse";
// renamed sqlStatement to sqlDocument
var sqlDocument = CAD.getCache().getOrOpenAsync(query, 'myUniverseData_xml' );
var recordCount = sqlDocument.selectNodes("//record").getLength();
CAD.getCache().setDocument('commonUniverseData_xml', sqlDocument);
CAD.getJSXByName("blkMessage").setText(recordCount + " records in set. ",true);
//CAD.getJSXByName("grid" + topic).repaintData(); // XML bind will repaint on new cache doc
//CAD.getJSXByName("SearchFilter").repaint(); // Did the filter change? don't repaint if you don't have to.
}
