Ever wonder why the page appears frozen or why you get a dialog saying, "this script is taking too long"? Inside of the browser, JavaScript and the page's UI are very intertwined, which means they can affect each other and, in turn, affect overall page performance. Ensuring the fastest execution time of JavaScript code isn't about geek cred, it's about ensuring that the user experience is as fast and responsive as possible. In a world where an extra second can cost you a visitor, sluggishness due to poor JavaScript code is a big problem. In this talk, you'll learn what's going on inside the browser that can slow JavaScript down and how that can end up creating a "slow page". You'll also learn how to overcome the conspiracy against your code by eliminating performance bottlenecks.
34. 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
42. Result
UI Thread
time
Download See ya!Hello world! Parse Run
The UI thread needs to wait for the script to
download, parse, and run before continuing
43. Result
UI Thread
Download time takes the longest and is variable
Variable Constant
UI Thread
Download See ya!Hello world! Parse Run
46. Result
UI Thread
time
JavaScript UI UpdateUI Update
The more scripts to download in between UI
updates, the longer the page takes to render
JavaScript JavaScript
50. Put Scripts at Bottom
UI Thread
time
JavaScriptUI UpdateUI Update
Even if there are multiple scripts, the page
renders quickly
JavaScript JavaScript
62. Using Dynamic Scripts
UI Thread
time
Download
See ya!Hello world!
Parse
Run
Only code execution happens on the UI thread,
which means less blocking of UI updates
UI Update
66. Using Dynamic Scripts
UI Thread
time
Download
See ya!Hello world!
Parse
Run
Depending on time to download and script size,
execution may happen before next UI update
UI Update
70. Deferred scripts begin to
download immediately,
but don't execute until all UI
updates complete
71. Using <script defer>
UI Thread
time
Download
See ya!Hello world!
Parse
Run
Similar to dynamic script nodes, but with a
guarantee that execution will happen last
More UI More UI
72. Timing Note:
Although scripts always execute after
UI updates complete, the order of
multiple <script defer> scripts is not
guaranteed across browsers
77. Using <script async>
UI Thread
time
Download
See ya!Hello world!
Parse
Run
Download begins immediately and execution is
slotted in at first available spot
UI Update
82. //create a new timer and delay by 500ms
setTimeout(function(){
//code to execute here
}, 500)
setTimeout() schedules a function to be
added to the UI queue after a delay
83. 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);
}
94. Web Workers
●
Asynchronous JavaScript execution
●
Execution happens outside of UI thread
●
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
95. //in page
var worker = new Worker("process.js");
worker.onmessage = function(event){
useData(event.data);
};
worker.postMessage(values);
//in process.js
self.onmessage = function(event){
var items = event.data;
for (var i=0,len=items.length; i < len; i++){
process(items[i]);
}
self.postMessage(items);
};
108. A repaint occurs when a visual change doesn't
require recalculation of layout
Changes to visibility, colors (text/background), background images, etc.
110. A reflow occurs when a visual change
requires a change in layout
Initial page load ▪ browser resize ▪ DOM structure change ▪ layout style change
layout information retrieved
112. Repaints and reflows are queued
up as JavaScript executes
and then executed in order
113. Reflow
var list = document.getElementsByClassName("items")[0],
i, item;
for (i=0; i < 10; i++){
item = document.createElement("li");
item.innerHTML = "Item #" + i;
list.appendChild(item);
}
Reflow x 10!
116. 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
117. 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
118. DocumentFragment
var list = document.getElementsByClassName("items")[0],
fragment = document.createDocumentFragment(),
i, item;
for (i=0; i < 10; i++){
item = document.createElement("li");
item.innerHTML = "Item #" + i;
fragment.appendChild(item);
}
list.appendChild(fragment);
1 Reflow
125. 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
130. After all, all browsers now have
optimizing JavaScript engines
Tracemonkey/
JaegarMonkey
(3.5+)
V8
(all)
Squirrelfish
(4+)
Chakra
(9+)
Karakan
(10.5+)
142. Avoid Slow Loading JavaScript
• Put scripts at the bottom
• Concatenate scripts into as few files as
possible
• Choose the right way to load your scripts
– Dynamically created scripts
– Deferred scripts
– Asynchronous scripts
143. Avoid Slow JavaScript
• Don't allow JavaScript to execute for more
than 50ms
• Break up long JavaScript processes using:
– Timers
– Web Workers
144. 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