Building High Perf Web Apps - IE8 Firestarter - Presentation Transcript
2
3
Building High-Performance Web
Applications and Sites
John Hrvatin, Lead Program Manager
johnhrv@microsoft.com
4
Session Objective(s):
How to make your site faster today
Principles to remember when building sites
Key Takeaways
Suggestions help in ALL browsers
No magic solutions
Consider maintainability
5
“…We are like dwarfs on the shoulders of
giants, so that we can see more than they,
and things at a greater distance, not by
virtue of any sharpness of sight on our part,
or any physical distinction, but because we
are carried high and raised up by their giant
size.\"
- Bernard of Chartres 1124
6
IE8 CPU usage: Top 100 Sites
Layout, Rende
ring, Formattin
16% g, …
JScript & DOM
84%
7
IE8 CPU usage: Top AJAX Sites
Layout, Rende
ring, Formattin
g, …
33%
67%
JScript & DOM
8
Minimize included styles
Unused styles increase download size
Browser must parse and match all selectors
Failures are expensive!
11
Simplify selectors
Complex element selectors are slow
When possible:
Use class- or ID-based selectors
Make element selectors as simple as possible
Use child instead of descendent selectors
Do not mix RTL and LTR styles
Minimizing included styles makes this easier
12
Simplify selectors
table tr td ul li {color: green;}
li#pass {color: green;}
ul li {color: purple;}
ul > li {color: purple;}
Don't use expressions
Slow – evaluated frequently
Not supported in IE8 Standards Mode!
14
Minimize Page Re-layouts
Poor user experience as content moves
Browser performs unnecessary work
15
16
Takeaways
Minimize included styles
Use less-complicated selectors
Don’t use expressions
Minimize page re-layouts
Simplify!
17
Implicit lookups: Batch changes
function BuildUI2()
{
var elm = document.getElementById('ui');
1 innerHTML
// Generate UI
Reference
var contents = BuildTitle()
+ BuildBody()
+ BuildFooter();
// Replace existing contents with UI
elm.innerHTML = contents;
}
Multiple DOM lookups
function CalculateSum()
{
// Retrieve Values
document.body.all
var lSide = document.body.all.lSide.value;
document.body.all
var rSide = document.body.all.rSide.value;
// Generate Result
document.body.all.result.value = lSide
document.body.all
+ rSide;
}
Multiple DOM lookups: Cache references
function CalculateSum2()
{
// Cache Element Collection
var elms = document.body.all;
// Retrieve Values
elms
var lSide = elms.lSide.value;
elms
var rSide = elms.rSide.value;
// Generate Result
elms
elms.result.value = lSide + rSide;
}
Function lookups
function IterateWorkOverCollection()
{
var length = myCollection.length;
for(var i = 0; i < length; i++)
{
Work
Work(myCollection[i]);
}
}
Function lookups: Cache pointers
function IterateWorkOverCollection2()
{
var funcWork = Work;
var funcWork = Work;
var length = myCollection.length;
for(var i = 0; i < length; i++)
{
funcWork
funcWork(myCollection[i]);
}
}
Takeaways
Watch for expensive name lookups
Cache repeated lookups to local variables
Optimize only when needed
Consider maintainability
28
Parsing JSON
With eval
Requires new script execution context (slow)
Less secure
With custom library
More secure, but even slower
31
Parsing JSON: Use the native methods
Built-in JSON methods:
JSON.parse()
JSON.stringify()
toJSON() on prototypes of Date, Number, String,
and Boolean
Native equivalent of the reference parser from
http://wiki.ecmascript.org/doku.php?id=es3.1:json
_support
As safe as http://www.json.org/json_parser.js
but faster
32
33
The switch statement
switch(option)
{
case 1: …
case 2: …
case 3: …
…
case 1000: …
}
The switch statement: Use a lookup table
var lookup = {
1: function(){…}
2: function(){…}
3: function(){…}
…
1000: function(){…}
}
try {
lookup[option]();
lookup [option]();
} catch(e) {
// Default operation
}
Property access methods: Use direct access
this.property = foo();
Property access methods
Instantiating DOM functions
Problems: Costly (in CPU cycles)
Consider: Caching function pointers,
batching changes
Why: Generic Script Interface
38
Minimize DOM interaction
Scope Prototype
var name obj.name
DOM
Global
Prototype
Intermediate
…
… Cost
Instance
Local
39
Minimize DOM interaction
Scope Prototype
var name obj.name
DOM
Global
Prototype
Intermediate
…
… Cost
Instance
Local
40
Minimize DOM interaction
Trident (MSHTML)
DOM
JScript Engine
41
Minimize DOM interaction
function getElementsByClassName(className, node, tag) {
…
var elements = node.getElementsByTagName(tag);
var elements = node.getElementsByTagName(tag);
var pattern = new RegExp(\"(^|\\\\s)\" + className +
\"(\\\\s|$)\");
elements.length
for(var i = 0, j = 0; i < elements.length; i++) {
elements[i]
if (pattern.test(elements[i].className)) {
classElements[j] = elements[i];
j++;
}
}
return classElements;
}
Minimize DOM interaction
function getElementsByClassName(className, node, tag)
{
…
var results = node.getElementsByTagName(tag);
var elements = new Array(results.length);
var elements = new Array(results.length);
while (length--) elements[length] = results[length];
while (length--) elements[length] = results[length];
var pattern = new RegExp(\"(^|\\\\s)\" + className +
\"(\\\\s|$)\");
for(var i = 0, j = 0; i < elements.length i++) {
elements.length;
elements[i]
if (pattern.test(elements[i].className)) {
classElements.push(results[i]); j++;
}
} return classElements;
}
Smart use of DOM Methods
Smart use of DOM methods can minimize
overall DOM interaction
nextSibling() better than childNodes[i]
querySelectorAll() better for element groups
44
Smart use of DOM methods
function LoopChildren(elm)
{
var nodes = elm.childNodes;
var length = nodes.length;
for(var i = 0; i < length; i++)
{
var node = nodes[i];
nodes[i];
…
}
}
Smart use of DOM methods
function LoopChildren2(elm)
{
var node = elm.firstChild;
while(node != null)
{
…
node = node.nextSibling;
}
}
Use querySelectorAll for groups
function doValidation2()
{
// Retrieve the required elements by using Selectors
// Selects all form fields with 'required' classes
var reqs = document.querySelectorAll
document.querySelectorAll(\".required\");
// Set the flag to false by default
var missingRequiredField = false;
// Validate that the form data is not empty
for (var i = 0; i < reqs.length; i++) {
if (reqs[i].value == \"\")
missingRequiredField = true;
}
}
Takeaways
Use the native JSON object
Turn large switch statements into lookups
Avoid property access methods
Minimize DOM interaction
Use querySelectorAll for groups
Optimize only when needed
Consider maintainability
49
Tools
Fiddler
Inspect network traffic
www.fiddler2.com
neXpert
Fiddler plug-in to aid performance testing
http://www.fiddler2.com/fiddler2/addons/neXper
t.asp
64
Takeaways
Reduce the number of requests
Combine external scripts, styles, and images
Use caching
Reduce the size of requests
Use HTTP compression
Use conditional requests
Avoid blocking factors
Put script at end of HTML
65
Identify the performance bottleneck
Network / Bandwidth – using Fiddler
JavaScript – using Developer Tools
Aggressive DOM access – using Developer Tools
Reduce, Simplify, Re-factor
Reduce the bytes sent between the client/server
Simplify your code to avoid costly JavaScript and CSS
constructs
Cache DOM properties and function pointers
66
Video recordings of this session can be found here: more
Video recordings of this session can be found here:
1. http://channel9.msdn.com/tags/IE%208%20Firestarter - (Developer)
2. http://edge.technet.com/Tags/IE+8+Firestarter/ - (IT Pro's)
If you need to download this file, or need more infomation contact Mithun Dhar via http://blogs.msdn.com/mithund less
0 comments
Post a comment