125
High Performance JavaScript Nicholas C. Zakas | CapitolJS | September 18, 2011

High Performance JavaScript (CapitolJS 2011)

Embed Size (px)

Citation preview

Page 1: High Performance JavaScript (CapitolJS 2011)

High Performance JavaScript

Nicholas C. Zakas | CapitolJS | September 18, 2011Nicholas C. Zakas | CapitolJS | September 18, 2011

Page 2: High Performance JavaScript (CapitolJS 2011)

Who's this guy?

Co-Creator csslint.net

Contributor,Creator of YUI

Test

Author Lead Author Contributor Lead Author

Ex-tech leadYahoo!

Page 3: High Performance JavaScript (CapitolJS 2011)

@slicknet

(complaints: @voodootikigod)

Page 4: High Performance JavaScript (CapitolJS 2011)

Does JavaScript performance matter?

Page 5: High Performance JavaScript (CapitolJS 2011)
Page 6: High Performance JavaScript (CapitolJS 2011)
Page 7: High Performance JavaScript (CapitolJS 2011)
Page 8: High Performance JavaScript (CapitolJS 2011)

All browsers now haveoptimizing JavaScript engines

Tracemonkey/JaegarMonkey

(3.5+)

V8(all)

Nitro(4+)

Chakra(9+)

Karakan(10.5+)

Page 9: High Performance JavaScript (CapitolJS 2011)

http://ie.microsoft.com/testdrive/benchmarks/sunspider/default.html

Page 10: High Performance JavaScript (CapitolJS 2011)

Old computers ran slow applicationsSmall amounts of CPU power and memory

Page 11: High Performance JavaScript (CapitolJS 2011)

New computers are generally faster butslow applications still exist

More CPU + more memory = less disciplined application development

Page 12: High Performance JavaScript (CapitolJS 2011)
Page 13: High Performance JavaScript (CapitolJS 2011)

Oh yeah, one more thing

Page 14: High Performance JavaScript (CapitolJS 2011)
Page 15: High Performance JavaScript (CapitolJS 2011)
Page 16: High Performance JavaScript (CapitolJS 2011)
Page 17: High Performance JavaScript (CapitolJS 2011)

It's still possible to write slow JavaScript

Page 18: High Performance JavaScript (CapitolJS 2011)

JavaScript performancedirectly

affects user experience

Page 19: High Performance JavaScript (CapitolJS 2011)

The UI Threadaka Browser Event Loop

Page 20: High Performance JavaScript (CapitolJS 2011)

The browser UI thread is responsible forboth UI updates and JavaScript execution

Only one can happen at a time

Page 21: High Performance JavaScript (CapitolJS 2011)

Jobs for UI updates and JavaScript execution

are added to a UI queueEach job must wait in line for its turn to execute

Page 22: High Performance JavaScript (CapitolJS 2011)

<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>

<script type="text/javascript">

window.onload = function(){

document.getElementById("btn").onclick = function(){

//do something

};

};

</script>

Page 23: High Performance JavaScript (CapitolJS 2011)

Before Click

UI Thread

UI Queue

timetime

Page 24: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 25: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Draw down stateDraw down state

Page 26: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 27: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick UI UpdateUI UpdateUI UpdateUI Update

Draw up stateDraw up state

Page 28: High Performance JavaScript (CapitolJS 2011)

No UI updates while JavaScript is executing

Page 29: High Performance JavaScript (CapitolJS 2011)

JavaScript May Cause UI Update

<button id="btn" style="font-size: 30px; padding: 0.5em 1em">Click Me</button>

<script type="text/javascript">

window.onload = function(){

document.getElementById("btn").onclick = function(){

var div = document.createElement(“div”);

div.className = “tip”;

div.innerHTML = “You clicked me!”;

document.body.appendChild(div);

};

};

</script>

Page 30: High Performance JavaScript (CapitolJS 2011)

A UI update must use the latest info available

Page 31: High Performance JavaScript (CapitolJS 2011)

Long-running JavaScript=

Unresponsive UI

Page 32: High Performance JavaScript (CapitolJS 2011)

Responsive UI

UI Thread

timetime

JavaScriptJavaScript UI UpdateUI UpdateUI UpdateUI Update

Page 33: High Performance JavaScript (CapitolJS 2011)

Unresponsive UI

UI Thread

timetime

JavaScriptJavaScript UI UpdateUI UpdateUI UpdateUI Update

Page 34: High Performance JavaScript (CapitolJS 2011)

The longer JavaScript runs,the worse the user

experience

Page 35: High Performance JavaScript (CapitolJS 2011)

The runaway script timer prevents JavaScript

from running for too longEach browser imposes its own limit (except Opera)

Page 36: High Performance JavaScript (CapitolJS 2011)

Internet Explorer

Page 37: High Performance JavaScript (CapitolJS 2011)

Firefox

Page 38: High Performance JavaScript (CapitolJS 2011)

Safari

Page 39: High Performance JavaScript (CapitolJS 2011)

Chrome

Page 40: High Performance JavaScript (CapitolJS 2011)
Page 41: High Performance JavaScript (CapitolJS 2011)

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

Page 42: High Performance JavaScript (CapitolJS 2011)

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

Page 43: High Performance JavaScript (CapitolJS 2011)

Translation:No single JavaScript job should

execute for more than 100ms to ensure a responsive UI

Page 44: High Performance JavaScript (CapitolJS 2011)

Recommendation:Limit JavaScript execution to no

more than 50ms

measured on IE6 :)

Page 45: High Performance JavaScript (CapitolJS 2011)

Loadtime TechniquesDon't let JavaScript interfere with page load performance

Page 46: High Performance JavaScript (CapitolJS 2011)

During page load, JavaScript takes more time on the UI

thread

Page 47: High Performance JavaScript (CapitolJS 2011)

<!doctype html>

<html>

<head>

<title>Example</title>

</head>

<body>

<p>Hello world!</p>

<script src="foo.js"></script>

<p>See ya!</p>

</body>

</html>

Page 48: High Performance JavaScript (CapitolJS 2011)

Result

UI Thread

timetime

JavaScriptJavaScript UI UpdateUI UpdateUI UpdateUI Update

Page 49: High Performance JavaScript (CapitolJS 2011)

Result

UI Thread

timetime

foo.jsfoo.js See ya!See ya!Hello world!Hello world!

Page 50: High Performance JavaScript (CapitolJS 2011)

Result

UI Thread

timetime

DownloadDownload See ya!See ya!Hello world!Hello world! ParseParse RunRun

The UI thread needs to wait for the script todownload, parse, and run before continuing

Page 51: High Performance JavaScript (CapitolJS 2011)

Result

UI Thread

DownloadDownload See ya!See ya!Hello world!Hello world! ParseParse RunRun

Download time takes the longest and is variable

Variable Constant

Page 52: High Performance JavaScript (CapitolJS 2011)

Translation:The page doesn't render while

JavaScript is downloading, parsing, or executing during page

load

Page 53: High Performance JavaScript (CapitolJS 2011)

<!doctype html>

<html>

<head>

<title>Example</title>

</head>

<body>

<script src="foo.js"></script>

<p>Hello world!</p>

<script src="bar.js"></script>

<p>See ya!</p>

<script src="baz.js"></script>

<p>Uh oh!</p>

</body>

</html>

Page 54: High Performance JavaScript (CapitolJS 2011)

Result

UI Thread

timetime

JavaScriptJavaScript UI UpdateUI UpdateUI UpdateUI Update

The more scripts to download in between UI

updates, the longer the page takes to render

JavaScriptJavaScript JavaScriptJavaScript

Page 55: High Performance JavaScript (CapitolJS 2011)

Technique #1: Load scripts dynamically

Page 56: High Performance JavaScript (CapitolJS 2011)

var script = document.createElement("script"),

body;

script.type = "text/javascript";

script.src = "foo.js";

body.insertBefore(script, body.firstChild);

Basic Technique

Dynamically loaded scripts are non-blocking

Page 57: High Performance JavaScript (CapitolJS 2011)

Downloads no longer block the UI thread

Page 58: High Performance JavaScript (CapitolJS 2011)

<!doctype html>

<html>

<head>

<title>Example</title>

</head>

<body>

<p>Hello world!</p>

<script src="foo.js"></script>

<p>See ya!</p>

</body>

</html>

Page 59: High Performance JavaScript (CapitolJS 2011)

Using HTML <script>

UI Thread

timetime

DownloadDownload See ya!See ya!Hello world!Hello world! ParseParse RunRun

Page 60: High Performance JavaScript (CapitolJS 2011)

<!doctype html>

<html>

<head>

<title>Example</title>

</head>

<body>

<p>Hello world!</p>

<script>

var script = document.createElement("script"),

body = document.body;

script.type = "text/javascript";

script.src = "foo.js";

body.insertBefore(script, body.firstChild);

</script>

<p>See ya!</p><!-- more content -->

</body>

</html>

Page 61: High Performance JavaScript (CapitolJS 2011)

Using Dynamic Scripts

UI Thread

timetime

DownloadDownload

See ya!See ya!Hello world!Hello world!

ParseParse

RunRun

Only code execution happens on the UI thread,

which means less blocking of UI updates

UI UpdateUI Update

Page 62: High Performance JavaScript (CapitolJS 2011)

function loadScript(url, callback){

var script = document.createElement("script"), body = document.body;script.type = "text/javascript";

if (script.readyState){ //IE <= 8 script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; callback(); } };} else { //Others script.onload = function(){ callback(); };}

script.src = url;body.insertBefore(script, body.firstChild);

}

Page 63: High Performance JavaScript (CapitolJS 2011)

loadScript("foo.js", function(){

alert("Loaded!");

});

Usage

Page 64: High Performance JavaScript (CapitolJS 2011)

Timing Note:Script execution begins

immediately after download and parse – timing of execution is not

guaranteed

Page 65: High Performance JavaScript (CapitolJS 2011)

Technique #2: Defer scripts

Page 66: High Performance JavaScript (CapitolJS 2011)

<!doctype html>

<html>

<head>

<title>Example</title>

</head>

<body>

<p>Hello world!</p>

<script defer src="foo.js"></script>

<p>See ya!</p>

<!-- even more markup -->

</body>

</html>

Page 67: High Performance JavaScript (CapitolJS 2011)

Support for <script defer>

3.5

7.0

5.0

4.0

?

Page 68: High Performance JavaScript (CapitolJS 2011)

Deferred scripts begin to download immediately,

but don't execute until all UI updates complete

Page 69: High Performance JavaScript (CapitolJS 2011)

Using <script defer>

UI Thread

timetime

DownloadDownload

See ya!See ya!Hello world!Hello world!

ParseParse

RunRun

Similar to dynamic script nodes, but with aguarantee that execution will happen last

More UIMore UI More UIMore UI

Page 70: High Performance JavaScript (CapitolJS 2011)

Timing Note:Although scripts always execute after UI updates complete, the

order of multiple <script defer> scripts is not guaranteed across

browsers

Page 71: High Performance JavaScript (CapitolJS 2011)

Technique #3: Asynchronous scripts

Page 72: High Performance JavaScript (CapitolJS 2011)

<!doctype html>

<html>

<head>

<title>Example</title>

</head>

<body>

<p>Hello world!</p>

<script async src="foo.js"></script>

<p>See ya!</p>

<!-- even more markup -->

</body>

</html>

Page 73: High Performance JavaScript (CapitolJS 2011)

Support for <script async>

3.6

7.0

5.0

10 ?

Page 74: High Performance JavaScript (CapitolJS 2011)

Asynchronous scripts behave a lot like dynamic scripts

Page 75: High Performance JavaScript (CapitolJS 2011)

Using <script async>

UI Thread

timetime

DownloadDownload

See ya!See ya!Hello world!Hello world!

ParseParse

RunRun

Download begins immediately and execution is

slotted in at first available spot

UI UpdateUI Update

Page 76: High Performance JavaScript (CapitolJS 2011)

Note:Order of execution is explicitly

not preserved for asynchronous scripts

Page 77: High Performance JavaScript (CapitolJS 2011)

Runtime TechniquesWays to ensure JavaScript doesn't run away

Page 78: High Performance JavaScript (CapitolJS 2011)

function processArray(items, process, callback){

for (var i=0,len=items.length; i < len; i++){

process(items[i]);

}

callback();

}

Page 79: High Performance JavaScript (CapitolJS 2011)

Technique #1: Timers

Page 80: High Performance JavaScript (CapitolJS 2011)

//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

Page 81: High Performance JavaScript (CapitolJS 2011)

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);

}

Page 82: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 83: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 84: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 85: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick

Page 86: High Performance JavaScript (CapitolJS 2011)

After 25ms

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick

JavaScriptJavaScript

Page 87: High Performance JavaScript (CapitolJS 2011)

After 25ms

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick JavaScriptJavaScript

Page 88: High Performance JavaScript (CapitolJS 2011)

After Another 25ms

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick JavaScriptJavaScript

JavaScriptJavaScript

Page 89: High Performance JavaScript (CapitolJS 2011)

After Another 25ms

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick JavaScriptJavaScript JavaScriptJavaScript

Page 90: High Performance JavaScript (CapitolJS 2011)

Technique #2: Script Yielding

NEW!

Page 91: High Performance JavaScript (CapitolJS 2011)
Page 92: High Performance JavaScript (CapitolJS 2011)

//delay a function until after UI updates are done

setImmediate(function(){

//code to execute here

});

setImmediate() adds code to the UI queue after pending UI updates are

finished

Page 93: High Performance JavaScript (CapitolJS 2011)

Support for Script Yielding

? ? ? 10 ?

msSetIntermediate()

Page 94: High Performance JavaScript (CapitolJS 2011)

function yieldingProcessArray(items, process, callback){

//create a clone of the original var todo = items.concat();

setImmediate(function(){

var start = +new Date();

do {

process(todo.shift());

} while (todo.length > 0 &&

(+new Date() - start < 50));

if (todo.length > 0){

setImmediate(arguments.callee);

} else {

callback(items);

}

});

}

Page 95: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 96: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 97: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 98: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick

Page 99: High Performance JavaScript (CapitolJS 2011)

After Last UI Update

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick

JavaScriptJavaScript

Page 100: High Performance JavaScript (CapitolJS 2011)

After Last UI Update

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick JavaScriptJavaScript

Page 101: High Performance JavaScript (CapitolJS 2011)

No Other UI Updates

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick JavaScriptJavaScript

JavaScriptJavaScript

Page 102: High Performance JavaScript (CapitolJS 2011)

No Other UI Updates

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick JavaScriptJavaScript JavaScriptJavaScript

Page 103: High Performance JavaScript (CapitolJS 2011)

Technique #3: Web Workers

Page 104: High Performance JavaScript (CapitolJS 2011)
Page 105: High Performance JavaScript (CapitolJS 2011)

Support for Web Workers

3.5

4.0

4.0

10 10.6

Page 106: High Performance JavaScript (CapitolJS 2011)

Web Workers• Asynchronous JavaScript execution• Execution happens outside the UI thread

– Doesn’t block UI updates• Data-Driven API

– Data is serialized going into and out of the worker

– No access to DOM or BOM– Separate execution environment

Page 107: High Performance JavaScript (CapitolJS 2011)

//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);

};

Page 108: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 109: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 110: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Page 111: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

onclickonclick

UI UpdateUI Update

UI UpdateUI Update

Worker Thread

Page 112: High Performance JavaScript (CapitolJS 2011)

When Clicked

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick

Worker Thread

JavaScriptJavaScript

Page 113: High Performance JavaScript (CapitolJS 2011)

Worker Thread Complete

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick

onmessageonmessage

Page 114: High Performance JavaScript (CapitolJS 2011)

Worker Thread Complete

UI Thread

UI Queue

timetime

UI UpdateUI UpdateUI UpdateUI Update onclickonclick onmessageonmessage

Page 115: High Performance JavaScript (CapitolJS 2011)

Recap

Page 116: High Performance JavaScript (CapitolJS 2011)

The browser UI thread is responsible forboth UI updates and JavaScript execution

Only one can happen at a time

Page 117: High Performance JavaScript (CapitolJS 2011)

Responsive UI

UI Thread

timetime

JavaScriptJavaScript UI UpdateUI UpdateUI UpdateUI Update

Page 118: High Performance JavaScript (CapitolJS 2011)

Unresponsive UI

UI Thread

timetime

JavaScriptJavaScript UI UpdateUI UpdateUI UpdateUI Update

Page 119: High Performance JavaScript (CapitolJS 2011)

Avoid Slow Loading JavaScript

• Dynamically created scripts• Deferred scripts• Asynchronous scripts

Page 120: High Performance JavaScript (CapitolJS 2011)

Avoid Slow JavaScript• Don't allow JavaScript to execute for

more than 50ms• Break up long JavaScript processes

using:– Timers– Script Yielding (future)– Web Workers

Page 121: High Performance JavaScript (CapitolJS 2011)
Page 122: High Performance JavaScript (CapitolJS 2011)
Page 123: High Performance JavaScript (CapitolJS 2011)

Etcetera•My blog: www.nczonline.net•Twitter: @slicknet•These Slides: slideshare.net/nzakas•Hire us: [email protected]

Page 124: High Performance JavaScript (CapitolJS 2011)

Questions?

Page 125: High Performance JavaScript (CapitolJS 2011)

Creative Commons Images Used

•http://www.flickr.com/photos/lrargerich/3115367361/

•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/

•http://www.flickr.com/photos/torley/2361164281/

•http://www.flickr.com/photos/ottoman42/455242/

•http://www.flickr.com/photos/goincase/3843348908/