high performance javascript - jquery conference sf bay area 2010
DESCRIPTION
Learn the inner workings of JavaScript to learn what makes things slow and how to speed them up. Heavily focused on DOM manipulation and UI updates.TRANSCRIPT
High Performance JavaScriptNicholas C. Zakas
Principal Front End Engineer, Yahoo!jQuery Conference – SF Bay Area, April 24 2010
Principal Front End Engineer
Contributor
Author
Things I Know About
jQuery
YUI
JavaScript
Professional Wrestling
Does this matter?
Old computers ran slow applications Small amounts of CPU power and memory
New computers are generally faster butslow applications still exist
More CPU + more memory = less disciplined application development
It's still possible to write slow JavaScript on the new, faster
JavaScript engines
How can I improve JavaScript performance?
How can I improve JavaScript performance?
How can I make this fast???
How can I improve JavaScript performance?
How can I make this fast???
Why is this so slow?????
Many aspects conspire to make JavaScript slow Awareness is the first step to solution
The UI ThreadThe brains of the operation
The browser UI thread is responsible forboth UI updates and JavaScript execution
Only one can happen at a time
Jobs for UI updates and JavaScript execution areadded to a UI queue if the UI thread is busy
Each job must wait in line for its turn to execute
<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>
<script type="text/javascript">$(document).ready(function(){ $("#btn").bind("click",function(){ //do something });});</script>
Before Click
UI Thread
UI Queue
time
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
Draw down state
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
When Clicked
UI Thread
UI Queue
time
onclick UI UpdateUI Update
Draw up state
No UI updates while JavaScript is executing!
JavaScript May Cause UI Update
<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>
<script type="text/javascript">$(document).ready(function(){ $("#btn").bind("click",function(){ $("body").append("<div class=\"tip\">You " +
"clicked me!</div>”); });});</script>
A UI update must use the latest info available
Long-running JavaScript=
Unresponsive UI
Responsive UI
UI Thread
time
JavaScript UI UpdateUI Update
Unresponsive UI
UI Thread
time
JavaScript UI UpdateUI Update
The runaway script timer prevents JavaScriptfrom running for too long
Each browser imposes its own limit (except Opera)
Internet Explorer
Firefox
Safari
Chrome
Runaway Script Timer Limits• Internet Explorer: 5 million statements• Firefox: 10 seconds• Safari: 5 seconds• Chrome: Unknown, hooks into normal crash
control mechanism• Opera: none
How Long Is Too Long?
“0.1 second [100ms] is about the limit for having the user feel that the system is reacting instantaneously, meaning that no special feedback is necessary except to display the result.”
- Jakob Nielsen
Translation:No single JavaScript job should execute for more than 100ms to
ensure a responsive UI
Recommendation:Limit JavaScript execution to no more
than 50ms
function processArray(items, process, callback){ for (var i=0,len=items.length; i < len; i++){ process(items[i]); } callback();}
Timers to the rescue!
JavaScript Timers
• Created using setTimeout()• Schedules a new JavaScript execution job for
some time in the future• When the delay is up, the job is added to the
UI queue– Note: This does not guarantee execution
after the delay, just that the job is added to the UI queue and will be executed when appropriate
JavaScript Timers
• For complex processing, split up into timed functionality
• Use timers to delay some processing for later
function timedProcessArray(items, process, callback){ //create a clone of the original
var todo = items.concat(); setTimeout(function(){ var start = +new Date(); do { process(todo.shift()); } while (todo.length > 0 && (+new Date() - start < 50)); if (todo.length > 0){ setTimeout(arguments.callee, 25); } else { callback(items); } }, 25);}
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
When Clicked
UI Thread
UI Queue
time
UI UpdateUI Update onclick
After 25ms
UI Thread
UI Queue
time
UI UpdateUI Update onclick
JavaScript
After 25ms
UI Thread
UI Queue
time
UI UpdateUI Update onclick JavaScript
After Another 25ms
UI Thread
UI Queue
time
UI UpdateUI Update onclick JavaScript
JavaScript
After Another 25ms
UI Thread
UI Queue
time
UI UpdateUI Update onclick JavaScript JavaScript
Web Workers to the rescue!
Web Workers
• Asynchronous JavaScript execution• Execution happens in a separate process
– Not on the UI thread = no UI delays• Data-driven API
– Data is serialized when sending data into or out of Worker
– No access to DOM, BOM– Completely separate execution
environment
//in pagevar worker = new Worker("process.js");worker.onmessage = function(event){ useData(event.data);};worker.postMessage(values);
//in process.jsself.onmessage = function(event){ var items = event.data; for (var i=0,len=items.length; i < len; i++){ process(items[i]); } self.postMessage(items);};
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
When Clicked
UI Thread
UI Queue
time
onclick
UI Update
UI Update
Worker Thread
When Clicked
UI Thread
UI Queue
time
UI UpdateUI Update onclick
Worker Thread
JavaScript
Worker Thread Complete
UI Thread
UI Queue
time
UI UpdateUI Update onclick
onmessage
Worker Thread Complete
UI Thread
UI Queue
time
UI UpdateUI Update onclick onmessage
Web Workers Support
4.04.03.53.5 4.04.0
Repaint and ReflowUI update jobs
Long UI updates=
Unresponsive UI
Unresponsive UI
UI Thread
time
JavaScript UI UpdateUI Update
Long UI updates=
Unresponsive UI=
Frustrated users
JavaScript can cause long UI updates
A repaint occurs when a visual change doesn't require recalculation of layout
Changes to visibility, colors (text/background), background images, etc.
Repaint
<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>
<script type="text/javascript">$(document).ready(function(){ $("#btn").bind("click",function(){ $(this).css({ color: "#f00" }); });});</script> Repaint!
A reflow occurs when a visual change requires a change in layout
Initial page load ▪ browser resize ▪ DOM structure change ▪ layout style changelayout information retrieved
Reflow
<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>
<script type="text/javascript">$(document).ready(function(){ $("#btn").bind("click",function(){ $("body").append("<div class=\"tip\">You " +
"clicked me!</div>”); });});</script> Reflow!
Repaints and reflows are queued up as JavaScript executes
Reflow
var list = $("ul.items");
for (var i=0; i < 10; i++){ list.append("<li>Item #" + i + "</li>");}
Reflow x 10!
Limiting repaints/reflows improves overall performance
Solution #1Perform DOM manipulations
off-document
Off-Document Operations
• Fast because there's no repaint/reflow• Techniques:
– Remove element from the document, make changes, insert back into document
– Set element's display to “none”, make changes, set display back to default
– Build up DOM changes on a DocumentFragment then apply all at once
DocumentFragment• A document-like object• Not visually represented• Considered to be owned by the document from
which it was created• When passed to appendChild(), appends all
of its children rather than itself
Reflow!
No reflow!
Solution #2Group Style Changes
$("span.example").css({ color: "red" });$("span.example").css({ height: "100px" });$("span.example").css({ fontSize: "25px" });$("span.example").css({ backgroundColor: "white" });
Repaint! Reflow!
Reflow!
Repaint!
.active { color: red; height: 100px; fontSize: 25px; background-color: white;}
$("span.example").addClass("active");
Reflow!
Grouping Style Changes
var item = document.getElementById("myItem");item.style.cssText = "color:red;height:100px;" + "font-size:25px;background-color: white");
Reflow!
Grouping Style Changes
Solution #3Avoid Accidental Reflow
$("div.example").css({ width: "100px"});
var width = $("div.example").width();
Reflow!
Accidental Reflow
What to do?• Minimize access to layout information
– offsetTop, offsetLeft, offsetWidth, offsetHeight– scrollTop, scrollLeft, scrollWidth, scrollHeight– clientTop, clientLeft, clientWidth, clientHeight– Most computed styles
• If a value is used more than once, store in local variable
Recap
Things I Know About
jQuery
YUI
JavaScript
Professional Wrestling
The browser UI thread is responsible forboth UI updates and JavaScript execution
Only one can happen at a time
Responsive UI
UI Thread
time
JavaScript UI UpdateUI Update
Unresponsive UI
UI Thread
time
JavaScript UI UpdateUI Update
Unresponsive UI
UI Thread
time
JavaScript UI UpdateUI Update
Avoid Slow JavaScript• Don't allow JavaScript to execute for more
than 50ms• Break up long JavaScript processes using:
– Timers– Web Workers
Avoid Long UI Updates• Be careful of repaint and reflow• Perform complex DOM operations off-
document– Remove elements and re-add them– Use DocumentFragment objects
• Group style changes together• Avoid accidental reflow
Questions?
Etcetera• My blog: www.nczonline.net• My email: [email protected]• Twitter: @slicknet
Creative Commons Images Used• http://www.flickr.com/photos/lrargerich/3115367361/
• http://www.flickr.com/photos/photomonkey/93277011/
• http://www.flickr.com/photos/hippie/2406411610/
• http://www.flickr.com/photos/55733754@N00/3325000738/
• http://www.flickr.com/photos/eurleif/255241547/
• http://www.flickr.com/photos/off_the_wall/3444915939/
• http://www.flickr.com/photos/wwarby/3296379139/
• http://www.flickr.com/photos/derekgavey/4358797365/
• http://www.flickr.com/photos/mulad/286641998/