Performance improvements tips and tricks

636 views

Published on

AJAX jquery performance improvements

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
636
On SlideShare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Performance improvements tips and tricks

  1. 1. Performance improvements tips and tricks Diego Bragato
  2. 2. Browsers• Chrome – Javascript is translated directly to assembly code in the browser• Mozilla / Firefox – codebase dates back to the code base of netscape, and the javascript engine is open source• Opera – The PC version sometimes lags a bit behind standards, but usability and new features are very high and copied over to other browsers (e.g.single menu button, splash page, tabbing, shading) – OPERA MINI is important for mobile market, probably the only decent cross platform browser for phones (but note that the code base and architecture is very different from the PC one)• Safari• IE – There are heavy differences between versions – notwithstanding it was the most used browser (the first round of the browser wars was won) – it has not been updated for more than 5 years across 2001 and 2006 – The future is IE9, but these bastards made it available only from windows vista forcing an OS upgrade (high compliance with acid3 test e.g. HTML5 and SVG)• http://acid3.acidtests.org/• http://en.wikipedia.org/wiki/Usage_share_of_web_browsers• There is overall agreements to move everything to web based applications and HTML5 (microsoft wants to enter the machintosh market for phones and is their only way to do it)
  3. 3. ApproachPerformance improvements shall be transparent to the existing functionality• Measure first• Choose what to improve (and why)• Understand the risks of breaking stuff• Choose a strategy• Then do it• Remeasure at the end“Pre-optimization is the root of all evil”
  4. 4. Patterns• Cross browser patterns – Same performance problem (i.e. same load spikes) are happening across all browsers (maybe diluted in time)• Non cross browser patterns – Not reproducible across browsers – E.g. the css engine of IE6 is very poor – Typical are IE6 / IE7 / IE8 specific
  5. 5. Tooling• Chrome debugger – Chrome specific• Speed trace – Chrome specific• Debug bar – IE specific – not totally reliable• Manual Profiling – Always works – It’s very slow – No graphics, no tooling, just plain and raw – It’s a lot of crap code added to the software that needs to be removed – E.g. with the simple implementation provided: you cannot trace two functions
  6. 6. Manual profilingfunction fnUpdateDataInDataTable(inputObject) { var ms1 = trace(); if(inputObject && inputObject.value!=){ var idValue = inputObject.id; var rowNumber = idValue.split("row")[1].split("Column")[0]; var columnNumber = idValue.split("Column")[1].split(""")[0]; var updatedDataElement = ""; if(validateTimeHours(inputObject)&& validateDecimal(inputObject)){ updatedDataElement = "<input type="text" class="textBox" size="2" maxlength="5" " + "name="textbox" id="row"+rowNumber+"Column"+columnNumber+"" " + "value=""+inputObject.value+"" onBlur="fnUpdateDataInDataTable(this)"/>"; } else { updatedDataElement = "<input type="text" class="textBox" size="2" maxlength="5" " + "name="textbox" id="row"+rowNumber+"Column"+columnNumber+"" " + "value="" onBlur="fnUpdateDataInDataTable(this)"/>"; } var ms2 = trace(); fnUpdateModel(inputObject.value,rowNumber,columnNumber-1); var ms3 = trace(); timeSheetDataTable.fnUpdate(updatedDataElement,rowNumber,columnNumber-1); var ms4 = trace(); fnUpdateTotals(); } var ms5 = trace(); alert(ms1+":"+ms2+":"+ms3 +":"+ ms4 +":"+ms5); // alert is done here not to interfere with measuraments}// just millisecs delta between last call and this callvar date = null;function trace(){ if(date==null){ date = new Date(); } var msecs = date.getSeconds()*1000 + date.getMilliseconds(); date = new Date(); msecs2 = date.getSeconds()*1000 + date.getMilliseconds(); return (msecs2-msecs);}
  7. 7. Typical cases• One of the steps requires most of the time (e.g. 300ms 10ms, 0 ms, 1ms) changes for this one are probably in the first traced block / function• Loops are tricky one step of 30ms in a loop of 10 rows ends up in a 300ms overhead.• Bad case in a loop (15 ms,30ms, 15ms, 0ms,15ms) changes for this one are scattered• In loops watch out for trace time that increase together with the number of iterations (e.g linear growth / exponential growth)
  8. 8. Closures and parallelism in javascript• Closure definition inside the code is called parallel to the main execution thread.• It’s an old powerful idea that dates back to LISP and SCHEME and was proposed for java 7 (e.g. ERLANG is based on that)• Take care: everything is spawned !• When doing manual profiling you quickly see that not everything is sequential as expected• The order of the code in the editor does not reflect the order of runtime execution• This can be very good (fast: everything is parallel) and very bad (totally unsafe, no built in language constraints)• You can code threading within the language itself and not as an external library as in java or C++.• It is one of the dogmas behind AJAX
  9. 9. ParallelizationSymptomsParallel Sequential
  10. 10. window.ehr.api.init( Was Sequential{ successHandler: function() { // //Localization Details // $.ajax( { type:"GET", url: "catalog/i18n.nl.xml", dataType: "xml", data: null, success: function(data) { …………………………………… ehr.api.timesheets.getTimesheet( { successHandler: function(data) { …………………………………… ehr.api.timesheets.getEmployeeDetails( { successHandler: function(data) { ………………………………………………… }, errorHandler:function(data) { alert("ERROR: Cannot load initial check mediator"); }, message:ehr.api.timesheetGlobal.jsonForGetEmployeeDetails } ); }, errorHandler: function( data ) { alert("ERROR: Cannot load initial timesheet"); }, message: ehr.api.timesheetGlobal.jsonForGetTimeSheet } ); }, error:function() { alert("ERROR: Cannot load localization details"); } } ); }, errorHandler: function() { alert("API failed to initialize"); }} );
  11. 11. window.ehr.api.init( Now is Parallel{ successHandler: function() { // //Localization Details // $.ajax( { type:"GET", url: "catalog/i18n.nl.xml", dataType: "xml", data: null, success: function(data) { …………………………………… ehr.api.timesheets.getTimesheet( { successHandler: function(data) { …………………………………… }, errorHandler: function( data ) { alert("ERROR: Cannot load initial timesheet"); }, message: ehr.api.timesheetGlobal.jsonForGetTimeSheet } ); ehr.api.timesheets.getEmployeeDetails( { successHandler: function(data) { …………………………………………….. }, errorHandler:function(data) { alert("ERROR: Cannot load initial check mediator"); }, message:ehr.api.timesheetGlobal.jsonForGetEmployeeDetails } ); }, error:function() { alert("ERROR: Cannot load localization details"); } } ); }, errorHandler: function() { alert("API failed to initialize"); }} );
  12. 12. Caching for IEStart from the hypothesis that IE (expecially IE6) does not cache at all// Turn on background image caching in IE// --------------------------------------if ( document && document.execCommand ){ try { document.execCommand( "BackgroundImageCache", false, true ); } catch ( e ) { }}
  13. 13. Css selectors for IEThis was incredibly slow matching because the matchingapi in IE6 is added by jquery on top and matching throughall ids of the document using getDocumentIDs() andloopingWas:- $("[id^=txtPresenceCode_]").change(function() {Now:+ $("#txtPresenceCode_"+rowNumber).change(function() {The new one use the basic api getDocumentID()
  14. 14. Loops what shall be in and what shall be outWas: // Loop through xml lines from the service $(jTimeSheet).find("Line").each( function() { ……… $(#tblUI3GridHeadertbody).addClass("grayBorder"); }} );Now is: // Loop through xml lines from the service $(jTimeSheet).find("Line").each( function() { ……… } $(#tblUI3GridHeader tbody).addClass("grayBorder");} );The tbody is global to the table adding a class is a modification of thedom in terms of the basic browser api, why do it within the loop on xmllines ?
  15. 15. Duplication of codeWas:- // TODO do sth better to avoid duplication of code- $("[id^=txtMonday_]").change( function() {- ehr.api.timesheetMain.updateOnChange(this,6);- } ).click( function() {- ehr.api.timesheetMain.openOverWerkPopup(this);- } );- $("[id^=txtTuesday_]").change( function() {- ehr.api.timesheetMain.updateOnChange(this,7);- } ).click( function() {- ehr.api.timesheetMain.openOverWerkPopup(this);-} );-……………….-// Same for each week day-……………….Now is:+ $("#txtMonday_"+rowNumber).addClass("changeable");+ $("#txtTuesday_"+rowNumber).addClass("changeable");+ $("#txtWednesday_"+rowNumber).addClass("changeable");+ $("#txtThrusday_"+rowNumber).addClass("changeable");+ $("#txtFriday_"+rowNumber).addClass("changeable");+ $("#txtSaturday_"+rowNumber).addClass("changeable");+ $("#txtSunday_"+rowNumber).addClass("changeable");And in one single place:$(".changeable").change( function() {+ var id = this.id.split("_")[1];+ ehr.api.timesheetMain.updateOnChange(this,id);+ } ).click( function() {+ ehr.api.timesheetMain.openOverWerkPopup(this);+ } ).focusin(function(event){+ $("#divToelichBox").hide();+ } );Binding events on classes is a much better approach instead of binding them for each of them, and there is less overhead in addingclasses in one place and binding one single event call in a single place
  16. 16. Avoid funny approaches focusin / focusout- $(.clsToelich).focusout( function() {-- var value = $(.clsToelich).val();- var hourFieldId = $(.clsToelich).attr("id").split("-")[1];- $("#"+hourFieldId).attr("toelich",value);- $(#divToelichBox).hide();--} );It’s unclear what this code is doing,focusin and out was added due to a selectionof rows issue. Was more or less useless.Avoid unused code, avoid unclear code, avoidfunny approaches that try to workaround realproblems, try to solve the real problemonly.

×