JavaScript Performance and
Best Practices
Doris Chen Ph.D. Developer Evangelist
http://blogs.msdn.com/b/dorischen/ Twitter @doristchen
Who am I?
• Developer Evangelist at Microsoft based in Silicon Valley, CA
– Blog: http://blogs.msdn.com/b/dorischen/
– Twitter @doristchen
– Email: [email protected]
• Has over 13 years of experience in the software industry focusing on
web technologies
• Spoke and published widely at JavaOne, O'Reilly, SD West, SD
Forum and worldwide User Groups meetings
• Before joining Microsoft, Doris Chen was a Technology Evangelist at
Sun Microsystems
• Doris received her Ph.D. from the University of California at Los
Angeles (UCLA)
Agenda
• Optimization Strategies
• JavaScript Best Practices
Ajaxify
• The client and server are in a dialog
• Make the messages between them as small as possible
• The client does not need a copy of the database
– just enough information to serve the user
• Don't rewrite the server application in JavaScript
Don't Optimize Without Measuring
• Intuitions are often wrong
• A single trial is unreliable. Timers can be off by as much as 15 msec
• Even accurate measurements can lead to wrong conclusions
Manual Timing Method
function myFunctionToTest() {
var start = new Date().getTime();
... // body of the function
var totalTime = new Date().getTime() - start;
}
Only speed up things that take a lot of
time
• If profiling shows that you are spending most of your time in A, don't bother optimizing C.
Don't Tune For Quirks
• Some browsers have surprising inefficiencies
• A trick that is faster on Browser A might be slower on Browser B
• The performance characteristics of the next generation may be significantly different
• Avoid short-term optimizations
Put stylesheets at the top (css)
> Want the browser to display whatever content it has as soon as possible Avoids flash of unstyled content or blank white
screen > Solution: put stylesheets in document head
allows the page to render progressively > CSS at the bottom:
prohibits progressive rendering in many browsers, including Internet Explorer
browsers block rendering to avoid having to redraw elements of the page if their styles change
Move scripts to the bottom (javascript)
> Scripts block parallel downloads across all hostnames
> Scripts block rendering of everything below them in the page
JavaScript Best Practices
> Provide a clean separation of content, CSS, and JavaScript
> De-reference unused objects
> Think Asynchronous
> Working with Objects
> Defer Loading Resources
> General JavaScript Coding Best Practices
11
Separation of content, CSS, and
JavaScript
> A rich web application user interface is made up of content (HTML/XHTML) styles (CSS) JavaScript
> Place CSS and JavaScript code in separate files Optimize the bandwidth usage by having CSS and
JavaScript file loaded only once
> Variables to decide using external or inline multiple page views per user per session many of pages re-use the same scripts and stylesheets
Inline or External
• Inline JavaScript and CSS in front page, but dynamically download the external files after the page has finished loading
<style>#Styles</style>
<body>The quick brown fox...</body>
<script type="text/javascript">
// JavaScript logic
<script>
-------------------------------------------------------------------------------------
• For multiple views per user, and reusable scripts/css:
<link rel="stylesheet" type="text/css"
href="cart.css">
<body>The quick brown fox...</body>
<script type="text/javascript" src="cart.js">
De-reference unused objects
//delete objects
var foo='Delete Me'; //do something with foo
delete foo;
// detach listeners
someElement.removeEventListener(type, fn, false);
// remove DOM elements
someElement.parentNode.removeChild(someElement);
// page onunload
window.onunload= function() { /*do something*/}
14
Think Asynchronous > Prevents browsers from halting execution of a
code block that might take a long time
> Semi-Asynchronous – Like an Ajax request
Use a callback
> use setTimeout() in conjunction with a callback
function longProcess({ name : value}, callback) {
// do what needs to be done
callback.apply({});
}
setTimeout(function() {
longProcess({ name : “doris”}, function() {
alert(“all done”);
}
}, 0);
Working with Objects (I)
var i;
for (i = 0; i < divs.length; i += 1) {
divs[i].style.color = "black";
divs[i].style.border = thickness + 'px solid blue';
divs[i].style.backgroundColor = "white";
}
-----------------------------------------------------------------------------------------------------------------------------------------------
var border = thickness + 'px solid blue';
var nrDivs = divs.length;
var ds, i;
for (i = 0; i < nrDivs; i += 1) {
ds = divs[i].style;
ds.color = "black";
ds.border = border;
ds.backgroundColor = "white";
}
Good
Strings
• Concatenation with + – Each operation allocates memory
– foo = a + b;
• Concatenate with array.join('') – The contents of an array are concatenated into a
single string
– foo = [a, b].join('');
Working with Objects (II) String Concatenation
window.tablebuilder = function() {
var _header, _rows = [];
this.setHeader = function(_headers) {
_header = "<tr><th>" + _headers.join("</th><th>") + "</tr>";
};
this.addRow = function(_cells) {
_rows.push("<tr><td>" + _cells.join("</td><td>") + "</td></tr>");
};
this.toString = function() {
return "<table>" + _header +
"<tbody>" + _rows.join("") + "</tbody>" +
"</table>";
};
};
Defer Loading Resources
> If you have a large library or set of libraries, you don't need to load everything when a page is loaded
> Resources can be html, scripts, or css
Use Ajax Request
Add script/css links using DOM
Example: Defer Loading Resources
<script>
var deferredLibs = [ '/resources/jquery.js' ,
'/resources/base.js'];
addLibraries(libs : deferredLibs,
function(args) {
// initialize components
});
</script>
Example: Defer Loading Resources (cont.)
function addLibraries( libs, callback) {
for(var i=0; i < libs.length; i+=1) {
var head =
document.getElementsByTagName("head")[0];
var s = document.createElement("script");
// add callback tracking logic
s.src = libs[i];
head.appendChild(s);
}
}
JavaScript Best Practices
> Provide a clean separation of content, CSS, and JavaScript
> De-reference unused objects
> Think Asynchronous
> Working with Objects
> Defer Loading Resources
> General JavaScript Coding Best Practices
22
Use === Instead of ==
• two different kinds of equality operators: === | !== and == | !=
• same type and value
– === true
– !== false
Eval = Bad
eval(string)
• eval function compiles and executes a string and returns the result
– gives us access to JavaScript’s compiler
• what the browser uses to convert strings into actions
• most misused feature of the language
– decreases script’s performance substantially
– also poses a huge security risk because it grants far too much power to the passed in text
• Avoid it if you can!
Don’t Use Short-Hand
• Technically, get away with omitting most curly braces and semi-colons
if(someVariableExists) x = false anotherfunctionCall();
Interpreted by some browsers if(someVariableExists) { x = false;} anotherFunctionCall(); ----------------------------------------------------------------------------------------------------------------------------- -----
if(someVariableExists) { x = false; anotherFunctionCall(); }
-----------------------------------------------------------------------------------------------------------------------------
Declare Variables Outside of the For
Statement
for(var i = 0; i < someArray.length; i++) { var container = document.getElementById('container'); container.innerHtml += 'my number: ' + i; console.log(i);
}
var container = document.getElementById('container'); for(var i = 0, len = someArray.length; i < len; i++) {
container.innerHtml += 'my number: ' + i; console.log(i);
}
----------------------------------------------------------------------------------------------------------------------
Reduce Globals
var name = doris'; var lastName = chen'; function doSomething() {...} console.log(name);
var DudeNameSpace = { name : 'Jeffrey', lastName : 'Way', doSomething : function() {...}
} console.log(DudeNameSpace.name);
"By reducing your global footprint to a single name, you significantly reduce the chance of bad interactions with other applications, widgets, or libraries." - Douglas Crockford
-----------------------------------------------------------------------------------------------------------------------------
Don't Pass a String to "SetInterval"
or "SetTimeOut"
• Never pass a string to SetInterval and SetTimeOut
setInterval( "document.getElementById('container').innerHTML += 'My new number: ' + i", 3000
);
setInterval(someFunction, 3000);
• Pass function name
Use {} Instead of New Object() var o = new Object(); o.name = 'Jeffrey'; o.lastName = 'Way'; o.someFunction = function() { console.log(this.name); }
var o = { name: 'Jeffrey', lastName = 'Way', someFunction : function() { console.log(this.name); }
};
var o = {}; //create empty object
----------------------------------------------------------------------------------------------------------------------
Use [] Instead of New Array()
var a = new Array(); a[0] = "Joe"; a[1] = 'Plumber';
var a = ['Joe','Plumber'];
----------------------------------------------------------------------------------------------------------------------
Code Quality
• High quality code is most likely to avoid platform problems.
• Code Conventions for the JavaScript Programming Language
– http://javascript.crockford.com/code.html
• Use JSLint.com. Pass with no warnings
JSLint -- Code Quality Tool
• JSLint can help improve the robustness and portability of your programs – enforces style rules
– spot some errors that are very difficult to find in debugging
– It can help eliminate implied globals
• Integrated with tools, Visual Studio 2010 – http://jslint4vs2010.codeplex.com/
• Resources – http://www.jslint.com/
– http://www.javascriptlint.com/download.htm
DOM Manipulation
• If JavaScript were infinitely fast, most pages would run at about the same speed.
• The bottleneck tends to be the DOM interface
• There is a significant cost every time you touch the DOM tree
• Each touch can result in a reflow computation, which is expensive
Make good use of Ajax Libraries
• Effective code reuse will make widgets more effective
• JavaScript Toolkits
– Wrap up ajax details in javascript libraries
– jQuery, Dojo, prototype+scriptaculous, YUI,...
Reduce the size of JavaScript file
• Reduce the amount of source code to reduce download time.
• Minification deletes whitespace and comments – While in development mode keep your scripts
readable so that they may be debugged easier
• Consider compressing your JavaScript resources when you deploy your application – If you use a 3rd party JavaScript library use the
compressed version if one is provided.
Gzip components (server)
> you can affect users' download times Gzip supported in more browsers Gzip generally reduces the response size by 70%
> Not just for html, gzip all scripts, stylesheets, XML, JSON but not images, PDF Content-Encoding: gzip
> Gzip configuration HTTP request
Accept-Encoding: gzip, deflate
HTTP response Content-Encoding: gzip
Resources
> Best practices and Guidelines http://developer.yahoo.com/performance/rules.ht
ml
> Useful Sites http://stevesouders.com/ http://javascript.crockford.com/
Upcoming Web Camps
2 Days HTML5 and Web Development WebCamp
May 20-May 21st, 2011, Mountain View, CA
Free, learning innovative web technology, hands on experience
JavaScript Performance and
Best Practices
Doris Chen Ph.D. Developer Evangelist
http://blogs.msdn.com/b/dorischen/ Twitter @doristchen