第1页
Writing Efficient JavaScript
What makes JavaScript slow and what to do about it
Nicholas C. Zakas Principal Front End Engineer, Yahoo! Velocity – June 2009
第2页
Who's this guy?
• Principal Front End Engineer, Yahoo! Homepage • YUI Contributor • Author
第4页
Why slow?
第5页
We grew up
第6页
Browsers didn't
第7页
In the Beginning
第8页
Now
第9页
What's the problem?
第10页
No compilation!*
* Humor me for now. It'll make this easier.
第12页
Browsers won't help your code!!!!
第13页
Didn't Matter Then
第14页
Didn't Matter Then
• JavaScript used for simple form validation or image hovers
• Slow Internet connections
– People expected to wait
• Click-and-go model • Each page contained very little code
第15页
Matters Now
第16页
Matters Now
• Ajax and Web 2.0 • More JavaScript code than ever before • Fast Internet connections
– People have come to expect speed
• Applications that stay open for a long time
– Gmail – Facebook
• Download and execute more code as you interact
第17页
Who will help your code?
第19页
Disclaimer
What follows are graphic depictions of the parts of JavaScript that are slow. Where appropriate, the names of the offenders have been changed to protect their identities. All of the data, unless otherwise noted, is for the browsers that are being used by the majority of web users right now, in 2009. The techniques presented herein will remain valid at least for the next 2-3 years. None of the techniques will have to be reversed once browsers with super powers are the norm and handle all optimizations for us. You should not take the techniques addressed in this presentation as things you should do all of the time. Measure your performance first, find the bottlenecks, then apply the appropriate techniques to help your specific bottlenecks. Premature optimization is fruitless and should be avoided at all costs.
第20页
JavaScript Performance Issues
• Scope management • Data access • Loops • DOM • Browser limits
第22页
Scope Chains
第23页
When a Function Executes
• An execution context is created
• The context's scope chain is initialized with the members of the function's [[Scope]] collection
• An activation object is created containing all local variables
• The activation object is pushed to the front of the context's scope chain
第24页
Execution Context
Identifier Resolution • Start at scope chain position 0 • If not found go to position 1 • Rinse, repeat
第25页
Identifier Resolution
• Local variables = fast!
• The further into the chain, the slower the resolution
第26页
Time (ms) per 200,000 reads
200 180 160 140 120 100
80 60 40 20
0 1
Identifier Resolution (Reads)
Firefox 3 Firefox 3.5 Beta 4 Chrome 1 Chrome 2 Internet Explorer 7 Internet Explorer 8 Opera 9.64 Opera 10 Beta Safari 3.2 Safari 4
23456 Identifier Depth
第27页
Time (ms) per 200,000 writes
200 180 160 140 120 100
80 60 40 20
0 1
Identifer Resolution (Writes)
Firefox 3 Firefox 3.5 Beta 4 Chrome 1 Chrome 2 Internet Explorer 7 Internet Explorer 8 Opera 9.64 Opera 10 Beta Safari 3.2 Safari 4
23456 Identifier Depth
第28页
Scope Chain Augmentation
• The with statement • The catch clause of try-catch • Both add an object to the front of the scope chain
第29页
Inside of Global Function
第30页
Inside of with/catch Statement
• Local variables now in second slot • with/catch variables now in first slot
第31页
“with statement considered harmful”
-Douglas Crockford
第32页
Closures
• The [[Scope]] property of closures begins with at least two objects
• Calling the closure means three objects in the scope chain (minimum)
第34页
Closures
第35页
Inside of Closure
第36页
Recommendations
• Store out-of-scope variables in local variables
– Especially global variables
• Avoid the with statement
– Adds another object to the scope chain, so local function variables are now one step away
– Use local variables instead
• Be careful with try-catch
– The catch clause also augments the scope chain
• Use closures sparingly • Don't forget var when declaring variables
第38页
JavaScript Performance Issues
• Scope management • Data access • Loops • DOM • Browser limits
第39页
Places to Access Data
• Literal value • Variable • Object property • Array item
第40页
Data Access Performance
• Accessing data from a literal or a local variable is fastest
– The difference between literal and local variable is negligible in most cases
• Accessing data from an object property or array item is more expensive
– Which is more expensive depends on the browser
第41页
Data Access
Time (ms) per 200,000 reads
Literal
Local Variable Array Item
Object Property
Firefox 3 Firefox 3.5 Chrome 1 Chrome 2 Internet Internet Opera 9.64 Opera 10 Safari 3.2
Beta 4
Explorer 7 Explorer 8
Beta
Safari 4
第42页
Property Depth
• object.name < object.name.name
• The deeper the property, the longer it takes to retrieve
第43页
Time (ms) per 200,000 reads
250 200 150 100
50 0 1
Property Depth (Reads)
23 Property Depth
Firefox 3 Firefox 3.5 Beta 4 Chrome 1 Chrome 2 Internet Explorer 7 Internet Explorer 8 Opera 9.64 Opera 10 Beta Safari 3.2 Safari 4
第44页
Property Notation
• Difference between object.name and object[“name”]?
– Generally no – Exception: Dot notation is faster in Safari
第45页
Recommendations
• Store these in a local variable:
– Any object property accessed more than once – Any array item accessed more than once
• Minimize deep object property/array item lookup
第47页
-5% -10% -33%
第48页
JavaScript Performance Issues
• Scope management • Data Access • Loops • DOM • Browser limits
第49页
Loops
• ECMA-262, 3rd Edition:
– for – for-in – do-while – while
• ECMA-357, 2nd Edition:
– for each
第51页
Which loop?
第52页
It doesn't matter!
第53页
What Does Matter?
• Amount of work done per iteration
– Includes terminal condition evaluation and incrementing/decrementing
• Number of iterations • These don't vary by loop type
第54页
Fixing Loops
• Decrease amount of work per iteration • Decrease number of iterations
第58页
Easy Fixes
• Eliminate object property/array item lookups
第60页
Easy Fixes
• Eliminate object property/array item lookups
• Combine control condition and control variable change
– Work avoidance!
第61页
Two evaluations: j < len j < len == true
第62页
One evaluation j-- == true
-50%
第63页
Easy Fixes
• Eliminate object property/array item lookups
• Combine control condition and control variable change
– Work avoidance!
第64页
Things to Avoid for Speed
• ECMA-262, 3rd Edition:
– for-in
• ECMA-357, 2nd Edition:
– for each
• ECMA-262, 5th Edition:
– array.forEach()
• Function-based iteration:
– jQuery.each() – Y.each() – $each – Enumerable.each()
第65页
• Introduces additional function • Function requires execution (execution context
created, destroyed) • Function also creates additional object in scope
chain
8x
第66页
JavaScript Performance Issues
• Scope management • Data Access • Loops • DOM • Browser limits
第67页
DOM
第68页
HTMLCollection
第69页
HTMLCollection Objects
• document.images, document.forms, etc.
• getElementsByTagName()
• getElementsByClassName()
第70页
Note: Collections in the HTML DOM are assumed to be live meaning that they are automatically updated when the underlying
document is changed.
第71页
Infinite Loop!
第72页
HTMLCollection Objects
• Look like arrays, but aren't
– Bracket notation – length property
• Represent the results of a specific query
• The query is re-run each time the object is accessed
– Include accessing length and specific items – Much slower than accessing the same on arrays – Exceptions: Opera, Safari
第73页
15x 53x 68x
第74页
===
第75页
HTMLCollection Objects
• Minimize property access
– Store length, items in local variables if used frequently
• If you need to access items in order frequently, copy into a regular array
第76页
function array(items){
try {
return Array.prototype.slice.call(items);
} catch (ex){
var i
= 0,
len = items.length,
result = Array(len);
while (i < len){ result[i] = items[i]; i++;
} }
return result; }
第77页
Repaint & Reflow
第78页
Repaint...is what happens
whenever something is made visible when it was not previously visible, or vice
versa, without altering the layout of the document.
- Mark 'Tarquin' Wilton-Jones, Opera
第79页
When Repaint?
• Change to visibility
• Formatting styles changed
– Backgrounds – Borders – Colors – Anything that doesn't change the size, shape, or
position of the element but does change its appearance
• When a reflow occurs
第80页
Reflow is the process by
which the geometry of the layout engine's formatting objects are computed.
- Chris Waterson, Mozilla
第81页
When Reflow?
• Initial page load • Browser window resize • DOM nodes added or removed • Layout styles applied • Layout information retrieved
第82页
Addressing Repaint & Reflow
• Perform DOM changes off-document • Groups style changes • Cache retrieved layout information
第83页
Reflow!
第84页
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
第85页
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
第86页
No reflow!
Reflow!
第87页
Addressing Repaint & Reflow
• Perform DOM changes off-document • Group style changes • Cache retrieved layout information
第88页
Repaint! Reflow! Reflow!
Repaint!
第89页
What to do?
• Minimize changes on style property
• Define CSS class with all changes and just change className property
• Set cssText on the element directly
第90页
Reflow!
第91页
Reflow!
第92页
Addressing Repaint & Reflow
• Perform DOM changes off-document • Group style changes • Cache retrieved layout information
– Reflow may be cached
第93页
Reflow?
Reflow?
Reflow?
第94页
What to do?
• Minimize access to layout information
• If a value is used more than once, store in local variable
第95页
Speed Up Your DOM
• Be careful using HTMLCollection objects • Perform DOM manipulations off the document • Group CSS changes to minimize repaint/reflow • Be careful when accessing layout information
第96页
JavaScript Performance Issues
• Scope management • Data Access • Loops • DOM • Browser limits
第97页
Call Stack
Runaway Timer
第98页
Call Stack
• Controls how many functions can be executed in a single process
• Varies depending on browser and JavaScript engine
• Errors occur when call stack size is exceeded
第99页
Note: Internet Explorer changes call stack size based on available memory
第100页
Call Stack Overflow
• Error messages
– IE: “Stack overflow at line x” – Firefox: “Too much recursion” – Safari: “Maximum call stack size exceeded.” – Opera: “Abort (control stack overflow)” – Chrome: n/a
• Browsers throw a regular JavaScript error when this occurs
– Exception: Opera just aborts the script
第101页
Runaway Script Timer
• Designed to prevent the browser from affecting the operating system
• Limits the amount of time a script is allowed to execute
• Two types of limits:
– Execution time – Number of statements
• Always pops up a scary dialog to the user
• Exception: Opera has no runaway timer
第102页
Internet Explorer
第103页
Firefox
第104页
Safari
第105页
Chrome
第106页
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
第107页
The Browser UI Thread
• Shared between JavaScript and UI updates • Only one can happen at a time • Page UI frozen while JavaScript is executing
• A queue of actions is kept containing what to do next
第108页
Browser Limit Causes
• Too much DOM interaction
– Repaint & reflow
• Too much recursion • Long-running loops
第110页
Recursion Pattern #1
第111页
Recursion Pattern #2
第112页
Recursion Solutions
• Iteration
第115页
Recursion Solutions
• Iteration • Memoization
第119页
Browser Limit Causes
• Too much DOM interaction
– Repaint & reflow
• Too much recursion • Long-running loops
– Too much per iteration – Too many iterations – Lock up the browser UI
第120页
setTimeout()
• Schedules a task to be added to the UI queue later • Can be used to yield the UI thread • Timer functions begin with a new call stack
• Extremely useful for avoiding browser limits
第121页
Loops galore!
第122页
Just do one pass
Defer the rest
第124页
Avoiding Browser Limits
• Mind your DOM
– Limit repaint/reflow
• Mind your recursion
– Consider iteration or memoization
• Mind your loops
– Keep small, sprinkle setTimeout() liberally if needed
第125页
Will it be like this forever?
第126页
No
第127页
Browsers With Optimizing Engines
• Chrome (V8) • Safari 4+ (Nitro) • Firefox 3.5+ (TraceMonkey) • Opera 10? 11? (Carakan)
All use native code generation and JIT compiling to achieve faster JavaScript execution.
第128页
Summary
第137页
Questions?
第138页
• My blog: • My email: • Twitter:
Etcetera
www.nczonline.net nzakas@yahoo-inc.com @slicknet
第139页
Creative Commons Images Used
• http://www.flickr.com/photos/neogabox/3367815587/ • http://www.flickr.com/photos/lydz/3355198458/ • http://www.flickr.com/photos/37287477@N00/515178157/ • http://www.flickr.com/photos/ottoman42/455242/ • http://www.flickr.com/photos/hippie/2406411610/ • http://www.flickr.com/photos/flightsaber/2204113449/ • http://www.flickr.com/photos/crumbs/2702429363/ • http://www.flickr.com/photos/oberazzi/318947873/ • http://www.flickr.com/photos/vox_efx/2912195591/ • http://www.flickr.com/photos/fornal/385054886/ • http://www.flickr.com/photos/29505605@N08/3198765320/ • http://www.flickr.com/photos/torley/2361164281/ • http://www.flickr.com/photos/rwp-roger/171490824/