Writing Efficient JavaScript discusses common issues that can slow down JavaScript performance and provides recommendations to address them. It covers scope management, data access, loops, DOM manipulation, and avoiding browser limits. The document recommends minimizing scope chain lookups, storing frequently accessed properties in local variables, optimizing loops, performing DOM changes off-document to reduce reflows, and using setTimeout() to avoid locking up the browser thread.
1 of 139
More Related Content
Writing Efficient JavaScript
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
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
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
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.
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
32. Closures
• The [[Scope]] property of closures begins with at
least two objects
• Calling the closure means three objects in the
scope chain (minimum)
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
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
100
90
80
70
Time (ms) per 200,000 reads
60
Literal
Local Variable
50
Array Item
Object Property
40
30
20
10
0
Firefox 3 Firefox 3.5 Chrome 1 Chrome 2 Internet Internet Opera 9.64 Opera 10 Safari 3.2 Safari 4
Beta 4 Explorer 7 Explorer 8 Beta
43. Property Depth (Reads)
250
200
Firefox 3
Time (ms) per 200,000 reads
Firefox 3.5 Beta 4
150 Chrome 1
Chrome 2
Internet Explorer 7
Internet Explorer 8
Opera 9.64
100 Opera 10 Beta
Safari 3.2
Safari 4
50
0
1 2 3 4
Property Depth
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
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
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
nd
• ECMA-357, 2 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
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
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;
}
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
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
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
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
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
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
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
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
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