performance improvements tips and tricks

24
Performance improvements tips and tricks Diego Bragato

Upload: diego-bragato

Post on 05-Jul-2015

387 views

Category:

Technology


2 download

DESCRIPTION

AJAX jquery performance improvements

TRANSCRIPT

Page 1: Performance improvements tips and tricks

Performance improvements

tips and tricks

Diego Bragato

Page 2: Performance improvements tips and tricks

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)

Page 3: Performance improvements tips and tricks

Approach

Performance 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”

Page 4: Performance improvements tips and tricks

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

Page 5: Performance improvements tips and tricks

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

Page 6: Performance improvements tips and tricks
Page 7: Performance improvements tips and tricks
Page 8: Performance improvements tips and tricks
Page 9: Performance improvements tips and tricks
Page 10: Performance improvements tips and tricks
Page 11: Performance improvements tips and tricks
Page 12: Performance improvements tips and tricks
Page 13: Performance improvements tips and tricks
Page 14: Performance improvements tips and tricks

Manual profiling

function 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 call

var 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);

}

Page 15: Performance improvements tips and tricks

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)

Page 16: Performance improvements tips and tricks

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

Page 17: Performance improvements tips and tricks

Parallelization

Symptoms

Parallel Sequential

Page 18: Performance improvements tips and tricks

Was Sequentialwindow.ehr.api.init(

{

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");

}

} );

Page 19: Performance improvements tips and tricks

Now is Parallelwindow.ehr.api.init(

{

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");

}

} );

Page 20: Performance improvements tips and tricks

Caching for IE

Start 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 ) { }

}

Page 21: Performance improvements tips and tricks

Css selectors for IE

This was incredibly slow matching because the matching

api in IE6 is added by jquery on top and matching through

all ids of the document using getDocumentIDs() and

looping

Was:- $("[id^=txtPresenceCode_]").change(function() {

Now:+ $("#txtPresenceCode_"+rowNumber).change(function() {

The new one use the basic api getDocumentID()

Page 22: Performance improvements tips and tricks

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 the dom in terms of the basic browser api, why do it within the loop on xml lines ?

Page 23: Performance improvements tips and tricks

Duplication of code

Was:

- // 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 adding classes in one place and binding one single event call in a single place

Page 24: Performance improvements tips and tricks

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 selection of rows issue. Was more or less useless.

Avoid unused code, avoid unclear code, avoid funny approaches that try to workaround real problems, try to solve the real problem only.