This document discusses strategies for improving JavaScript performance on websites. It begins by noting that JavaScript is often the number one cause of slow web pages. It then reviews the history of JavaScript loading approaches, from loading scripts in the page head in 1995 to more modern async and deferred loading. It discusses using localStorage as a cache and the Google Analytics async snippet as examples. It concludes by recommending tools and resources for measuring and improving JavaScript performance, including WebPagetest.org, ControlJS, and Steve Souders' own site and books.
10. 1995: scripts in HEAD
<head>
<script src=‘a.js’></script>
</head>
blocks other downloads (IE 6-7, images
in IE, iframes)
downloaded sequentially (IE 6-7)
blocks rendering during download &
parse-execute
11. 2007: move scripts to bottom
...
<script src=‘a.js’></script>
</body>
doesn’t block other downloads
downloaded sequentially in IE 6-7
blocks rendering during download &
parse-execute
12. 2009: load scripts async
var se =
document.createElement(‘script’)
;
se.src = ‘a.js’;
document.getElementsByTagName(‘he
ad’)[0].appendChild(se);
doesn’t block other downloads
downloaded in parallel (all browsers)
blocks rendering during parse-execute
13. 2010: async + on-demand exec
var se = new Image(); // Object
se.onload = registerScript;
se.src = ‘a.js’;
separate download from parse-execute
doesn’t block other downloads
downloaded in parallel (all browsers)
doesn’t block rendering until demanded
15. script async & defer
parsing doesn’t wait for script:
• async – executed when available
• defer – executed when parsing finished
when is it downloaded?
missing:
• defer download AND execution
• async/defer download, execute on demand
16. 20??: markup
<script src=‘a.js’
[async|defer|noexecute]
[deferdownload]>
doesn’t block downloads
downloaded in parallel
doesn’t block rendering until demanded
doesn’t contend for a connection
easier
17. ControlJS
a JavaScript module for making scripts load faster
just change HTML
inline & external scripts
<script type=‘text/cjs’
data-cjssrc=‘main.js’>
</script>
<script type=‘text/cjs’>
var name = getName();
</script>
http://controljs.org/
18. ControlJS
a JavaScript module for making scripts load faster
download without executing
<script type=‘text/cjs’
data-cjssrc=‘main.js’
data-cjsexec=false>
<script>
Later if/when needed:
CJS.execScript(src);
19. GMail Mobile
<script type=‘text/javascript’>
/*
var ...
*/
</script>
get script DOM element's text
remove comments
eval() when invoked
awesome for prefetching JS that might
(not) be needed
http://goo.gl/l5ZLQ
23. Home screen apps on iPhone are slower
because resources are re-requested
even though they should be read from
cache.
24. localStorage
window.localStorage:
setItem()
getItem()
removeItem()
clear()
also sessionStorage
all popular browsers, 5MB max
http://dev.w3.org/html5/webstorage/
http://diveintohtml5.org/storage.html
25. localStorage as cache
1st doc: write JS & CSS blocks to localStorage
mres.-0yDUQJ03U8Hjija: <script>(function(){...
set cookie with entries & version
MRES=-0yDUQJ03U8Hjija:-4EaJoFuDoX0iloI:...
later docs: read JS & CSS from localStorage
document.write( localStorage.getItem(mres.-
0yDUQJ03U8Hjija) );
http://stevesouders.com/blog/2011/03/28/storager-case-
study-bing-google/
26. Google Analytics Async Snippet
var ga = document.createElement(‘script’);
ga.type = ‘text/javascript’;
ga.async = true;
ga.src = (‘https:’ ==
document.location.protocol ? ‘https://ssl’ :
‘http://www’)+‘.google-analytics.com/ga.js’;
var s =
document.getElementsByTagName(‘script’)[
0];
s.parentNode.insertBefore(ga, s);
code.google.com/apis/analytics/docs/tracking/asyncTracking.html
27. var ga = document.createElement(‘script’);
ga.type = ‘text/javascript’;
ga.async = true;
ga.src = (‘https:’ ==
document.location.protocol ? ‘https://ssl’ :
‘http://www’)+‘.google-analytics.com/ga.js’;
var s =
document.getElementsByTagName(‘script’)[
0];
s.parentNode.insertBefore(ga, s);
avoid mixed content warning
protocol relative URLs have problems
set src last
stevesouders.com/blog/2010/02/10/5a-missing-schema-double-download/
28. var ga = document.createElement(‘script’);
ga.type = ‘text/javascript’;
ga.async = true;
ga.src = (‘https:’ ==
document.location.protocol ? ‘https://ssl’ :
‘http://www’)+‘.google-analytics.com/ga.js’;
var s =
document.getElementsByTagName(‘script’)[
0];
s.parentNode.insertBefore(ga, s);
previously:
getElementsByTagName(‘head’)[0].
appendChild(ga)
HEAD might not exist
stevesouders.com/blog/2010/05/11/appendchild-vs-insertbefore/
Android 1.5, iPhone 3.0, Opera 8.50, Safari 3.2
stevesouders.com/blog/2010/05/12/autohead-my-first-browserscope-user-test/
29. var ga = document.createElement(‘script’);
ga.type = ‘text/javascript’;
ga.async = true;
ga.src = (‘https:’ ==
document.location.protocol ? ‘https://ssl’ :
‘http://www’)+‘.google-analytics.com/ga.js’;
var s =
document.getElementsByTagName(‘script’)[
0];
s.parentNode.insertBefore(ga, s);
some browsers preserve execution order
Firefox 3.6, Opera, OmniWeb
stevesouders.com/tests/jsorder.php
3.777 seconds - http://www.webpagetest.org/result/120111_0P_2TW4Q/ - block “.js” (it’s not downloaded)5.471 seconds - http://www.webpagetest.org/result/120111_GR_2TW90/Alexa top 100wwide
median: 3.650vs 2.4873.777 seconds - http://www.webpagetest.org/result/120111_0P_2TW4Q/ - block “.js” (it’s not downloaded)5.471 seconds - http://www.webpagetest.org/result/120111_GR_2TW90/Alexa top 100wwide
flickr.com/photos/gevertulley/4771808965/Generallyasync & defer scripts start downloading immediately. I wish they’d wait, esp. defer scripts, so they don’t hog connections from the limited pool.subatomic particle traces