Javascript performance
I just went through some vedio related to javascript performance which is great, Here is the notes I made:
- Scope management
1. Identifier Resolution
Every time the function is executed, the execution context is created. The scope chain in the execution context stores the objects to be resolved in order.
sequence in the scope chain.
- with/catch
- local variables
- global variables
According to the scope chain, we can see the deeper you go the scope chain, the longer it take to resolve the identifers.
Recomendation:
- store out of scope varialbes in local variables, espeically global variables
- avoid With statement
- be careful with try/catch clause
- use sparsly closure.
- don't forget var when declaring variables
- Data access
Accessing data from literal variable and local variable is fartest.
Array item, object property look up takes more time.
property depth, the deeper the property, the longer it takes to retrieve. for example, object.name < object.name.name
property notation
object.name and object["name"] no difference generally. safari. dot notation is faster.
Recommendation
Store them in local variables, if the following happens:
1. if any object property accessed more than once.
2. any array item accessed more than once.
3. minimize deep object property/array item look up
example:
function process (data){ if(data.count>0) { for (var i=0;i<data.count;i++){ processdata(data.item[i]); } } }
after change made:
function process (data){ var count = data.count; item = data.item; if(count>0){ for(var i=0;i<count;i++) processdata(item[i]); }
- Loops
What does matter?
Amount of the work done per iteration, including the terminal condition evaluation incrementing/decrementing, here is the example:
for(var i=0;i<values.length;i++) { process (values[i]); }
Recommendation:
- Eliminate the object propery/array item lookups
- Combine control condition and control variable change - work avoidance
var len = values.length for (var i=len; i--;){ process(values[i]); }
- Avoid foreach statement which calls another function, here is the example:
values.foreach( function (data){ process(data); })
Reasons:
- Create execution context and destory
- The new execution context has its own scope chain.
Resolution:
8x peformance boost if we go with the regular loop like while, for, etc.
- DOM
1. HTMLCollection Objects.
document.images,
document.getElementsByTagName
They are automatcially updated when the uderlying document is changed.
var divs = document.getElementByTagName("div"); for(var i=0;i<div.length;i++){ var newdiv = document.createElement("div"); document.body.appendChild(newdiv); }
What the result if we run the script above:
infinite loop!! it's a infinite loop.
- HtmlCollection element look like arrays, but are not bracket notation, length property
- it represents the result of a specific query
- the query is re-run each time the object is accessed.
- including acessing lenth and specific items
- much slower than accessing the same on the arrays (exceptions: Opera, Safira). here is the example:
var items = [{},{},{},{},{},{},{}]; for( var i=0;i<items.length;i++){ } var divs = document.getElementByTagName("div"); for(var i=0;i<divs.length;i++){ }
the performance difference: firefox:15X; chrome: 53X; IE:68X
After change made: no much difference.
for( var i=0;len=divs.length;i<len;i++){ } for(var i=0;i<divs.length;i++){ }
Recommendaton:
- minimize accessing to the property of a object. store length, items in local variables if used frequently.
- if you need to access items in order frequently, copy into a regular array.
Reflow
When reflow happen
- Initial page load
- Browser window resize
- Layout style applied
- Add/remove dom node
- Layout information retrieved
How to avoid reflow:
- DocumentFragment
It's a dcoument-like object, consider a child of the document from which it was created, not visually represented, when you pass documentFragement to appendChild(), appends all of its children rather than itself.
var list = document.getElementById("list"); var fragment = document.createDocumentFragment(); for(var i=0;i<10;i++){ var item = document.createElement("li"); item.innerHTML = "Option #" + (i+1); fragment.appenChild(item); --No reflow } list.appenChild(fragment); --reflow
Recommendation:
- Minimize the changes on style property (element.style.height = "100PX")
- define CSS class with all changes and just change the className property
Layout information retrieved
all the statements below causes reflow:
var width = element.offsetwidth;
var scrollleft = element.scrollleft;
var display = window.getComputedStyle(div, '');
Recommendation on Speed up Dom:
- Be careful using HTMLCollection objects
- Perform DOM manipulation off the document
- Change CSS classes, not CSS styles
- Be careful when accessing layout information