JavaScript Performance Pa1erns @stoyanstefanov QCon San - - PowerPoint PPT Presentation

javascript performance pa1erns
SMART_READER_LITE
LIVE PREVIEW

JavaScript Performance Pa1erns @stoyanstefanov QCon San - - PowerPoint PPT Presentation

JavaScript Performance Pa1erns @stoyanstefanov QCon San Francisco, Nov 8, 2012 JavaScript Performance Pa1erns Importance of Performance h1p://bookofspeed.com


slide-1
SLIDE 1

JavaScript ¡Performance ¡Pa1erns ¡

@stoyanstefanov ¡ QCon ¡ San ¡Francisco, ¡Nov ¡8, ¡2012 ¡

slide-2
SLIDE 2

JavaScript ¡Performance ¡Pa1erns ¡

slide-3
SLIDE 3

Importance ¡of ¡Performance ¡

h1p://bookofspeed.com ¡ ¡

slide-4
SLIDE 4

Importance ¡of ¡JavaScript ¡Performance ¡

h1p://h1parchive.org ¡ ¡

slide-5
SLIDE 5

// ¡todo ¡

  • 1. Loading ¡JavaScript ¡
  • 2. RunJme ¡/ ¡UI ¡/ ¡DOM ¡

¡+ ¡benchmarks ¡ ¡+ ¡shims ¡

slide-6
SLIDE 6
slide-7
SLIDE 7
slide-8
SLIDE 8

Loading ¡

slide-9
SLIDE 9

First ¡things ¡first ¡

  • reduce ¡# ¡of ¡script ¡files ¡
  • gzip, ¡shave ¡70% ¡off ¡
  • minify, ¡extra ¡40-­‑50% ¡
  • Expires ¡headers ¡
  • CDN ¡

h1p://yslow.org ¡ PageSpeed ¡ ¡ h1p://webpagetest.org ¡ ¡

slide-10
SLIDE 10

<script ¡src="h1p://…"> ¡

NOPE! ¡

slide-11
SLIDE 11

SPOF ¡

  • Single ¡point ¡of ¡failure ¡
  • JS ¡blocks ¡

h1p://phpied.com/3po-­‑fail ¡ SPOF-­‑O-­‑MaJc: ¡ ¡h1ps://chrome.google.com/webstore/detail/plikhggdplemddobondkeogomgoodeg ¡ ¡

slide-12
SLIDE 12

Off ¡the ¡criJcal ¡path ¡

slide-13
SLIDE 13

Asynchronous ¡JS ¡

  • <script ¡defer> ¡
  • <script ¡async> ¡
  • unJl ¡then… ¡
slide-14
SLIDE 14

Dynamic ¡script ¡node ¡

var ¡js ¡= ¡document.createElement('script'); ¡ js.src ¡= ¡'h1p://cdn.com/my.js'; ¡ document.getElementsByTagName('head')[0].appendChild(js); ¡

h1p://calendar.perfplanet.com/2011/ the-­‑art-­‑and-­‑crao-­‑of-­‑the-­‑async-­‑snippet/ ¡

slide-15
SLIDE 15

But…, ¡bu1…, ¡bu1on? ¡

Q: ¡<button ¡onclick="…"? ¡ A: ¡To ¡hell ¡with ¡it ¡ ¡ Q: ¡Dependencies? ¡ A: ¡onload ¡event ¡and ¡js.onreadystatechange ¡ ¡

load('jquery.js', ¡'mystuff.js', ¡function ¡() ¡{ ¡ ¡ ¡mystuff.go(); ¡ }); ¡

slide-16
SLIDE 16

Unblocking ¡onload ¡

  • Async ¡JS ¡blocks ¡window.onload ¡in ¡!IE ¡
  • May ¡or ¡may ¡not ¡be ¡a ¡problem ¡
  • There's ¡a ¡soluJon: ¡FIF ¡
slide-17
SLIDE 17

<fif> ¡

frame-­‑in-­‑frame ¡aka ¡friendly ¡frames ¡ aka ¡this ¡Meebo ¡thing ¡

slide-18
SLIDE 18

FIF ¡

1) create ¡ iframe ¡src="js:false" ¡ 2) in ¡the ¡frame ¡doc.write ¡a ¡ ¡ <body ¡onload ¡… ¡ 3) …that ¡loads ¡JS ¡

slide-19
SLIDE 19

FIF ¡(snippet) ¡

var ¡iframe ¡= ¡document.createElement('iframe'); ¡ document.body.appendChild(iframe); ¡ var ¡doc ¡= ¡iframe.contentWindow.document; ¡ doc.open().write('<body ¡onload="'+ ¡ ¡ ¡'var ¡js ¡= ¡document.createElement(\'script\');'+ ¡ ¡ ¡'js.src ¡= ¡\'h1p://example.org/js.js\';'+ ¡ ¡ ¡'document.body.appendChild(js);">'); ¡ doc.close(); ¡

slide-20
SLIDE 20

FIF ¡

  • unblocks ¡onload, ¡but… ¡
  • more ¡complex ¡
  • requires ¡JS ¡changes ¡
slide-21
SLIDE 21

your ¡script ¡(before) ¡

¡ ¡ ¡ ¡// ¡fun ¡with ¡window ¡ ¡ ¡// ¡and ¡document ¡ ¡ ¡

slide-22
SLIDE 22

your ¡script ¡(before) ¡

(function() ¡{ ¡ ¡ ¡ ¡// ¡fun ¡with ¡window ¡ ¡ ¡// ¡and ¡document ¡ }()); ¡ ¡

slide-23
SLIDE 23

FIF ¡(aoer) ¡

(function(window) ¡{ ¡ ¡ ¡var ¡document ¡= ¡window.document; ¡ ¡ ¡// ¡fun ¡with ¡window ¡ ¡ ¡// ¡and ¡document ¡ }(parent.window)); ¡

slide-24
SLIDE 24

FIF ¡in ¡the ¡wild ¡

  • experimental ¡support ¡in ¡FB ¡JS ¡SDK ¡
  • h1p://jsbin.com/axibow/10/edit ¡ ¡ ¡

¡

slide-25
SLIDE 25

</fif> ¡

slide-26
SLIDE 26

Load ¡JS ¡but ¡not ¡execute ¡

  • Use ¡cases: ¡

– preload ¡in ¡anJcipaJon ¡ – lazy ¡

slide-27
SLIDE 27

Preload, ¡then ¡eventually ¡execute ¡

  • 1. fetch ¡the ¡script, ¡but ¡don’t ¡run ¡it ¡
  • 2. run ¡it ¡at ¡some ¡point ¡(same ¡as ¡async ¡JS) ¡
slide-28
SLIDE 28

Fetching ¡

  • IE: ¡dynamic ¡script ¡node, ¡not ¡in ¡the ¡DOM ¡
  • All ¡others: ¡CORS ¡(XHR2) ¡

– your ¡CDN ¡should ¡let ¡you ¡specify ¡ Access-­‑Control-­‑Allow-­‑Origin ¡ ¡ header ¡or ¡else! ¡

slide-29
SLIDE 29

Preload, ¡then ¡execute ¡

// preload var js = document.createElement('script'); if (!js.readyState || js.readyState !== 'uninitialized') { // non IE var xhr = new XMLHttpRequest(); if ('withCredentials' in xhr) { // XHR2 xhr.open('GET', url, false); xhr.send(null); } } js.src = url; // IE preloads! Thanks @getify // execute document.getElementsByTagName('head')[0].appendChild(js);

slide-30
SLIDE 30

// ¡todo ¡

  • 1. Loading ¡JavaScript ¡
  • 2. RunJme ¡/ ¡UI ¡/ ¡DOM ¡

¡+ ¡benchmarks ¡ ¡+ ¡shims ¡

slide-31
SLIDE 31

Benchmarks ¡

  • Lies, ¡damn ¡lies ¡and ¡performance ¡advice ¡
  • Test ¡the ¡wrong ¡thing ¡
  • Measure ¡the ¡wrong ¡thing ¡
  • Even ¡if ¡not, ¡sJll ¡draw ¡the ¡wrong ¡conclusions ¡
slide-32
SLIDE 32

Your ¡first ¡benchmark ¡

var ¡start ¡= ¡new ¡Date(); ¡ // ¡loop ¡100000 ¡times ¡ var ¡took ¡= ¡new ¡Date() ¡– ¡start; ¡

NOPE! ¡

slide-33
SLIDE 33

Benchmark.js ¡

  • by ¡John-­‑David ¡Dalton ¡
  • used ¡in ¡h1p://jsperf.com ¡ ¡

– calibraJng ¡the ¡test ¡ – end ¡Jme ¡(ops/second) ¡ – staJsJcal ¡significance ¡ – margin ¡of ¡error ¡

slide-34
SLIDE 34

h1p://calendar.perfplanet.com/2010/ bulletproof-­‑javascript-­‑benchmarks/ ¡ ¡

slide-35
SLIDE 35

Benchmarking ¡browsers? ¡

No, ¡thanks ¡

slide-36
SLIDE 36

Let's ¡test! ¡

slide-37
SLIDE 37

String ¡concat? ¡

var ¡text ¡= ¡""; ¡ text ¡+= ¡"moar"; ¡ ¡

  • vs. ¡

¡ var ¡parts ¡= ¡[]; ¡ parts.push('moar'); ¡ var ¡text ¡= ¡push.join(''); ¡

http://jsperf.com/join-concat/

slide-38
SLIDE 38

String ¡concat ¡

slide-39
SLIDE 39

The ¡pen ¡is ¡mighJer ¡than ¡the ¡sword! ¡* ¡

* ¡Only ¡if ¡the ¡sword ¡is ¡very ¡small ¡and ¡the ¡pen ¡very ¡sharp ¡

slide-40
SLIDE 40

"Don't ¡A, ¡B ¡is ¡so ¡much ¡faster!" ¡

You ¡should ¡check ¡it ¡again ¡

slide-41
SLIDE 41

Profiling ¡

slide-42
SLIDE 42
slide-43
SLIDE 43
slide-44
SLIDE 44
slide-45
SLIDE 45

Picking ¡ba1les ¡

slide-46
SLIDE 46

DOM ¡

slide-47
SLIDE 47

DOM ¡

  • DOM ¡is ¡slow ¡
  • How ¡slow? ¡ ¡
  • h1p://jsperf.com/dom-­‑touch ¡ ¡
slide-48
SLIDE 48

DOM ¡

// ¡DOM ¡ div.innerHTML ¡ ¡= ¡'a'; ¡ div.innerHTML ¡+= ¡'b'; ¡ ¡ // ¡string ¡ var ¡html ¡= ¡''; ¡ html ¡+= ¡'a'; ¡ html ¡+= ¡'b'; ¡ div.innerHTML ¡= ¡html; ¡

slide-49
SLIDE 49

DOM ¡

slide-50
SLIDE 50

DOM ¡+ ¡string ¡concat ¡

  • put ¡things ¡in ¡perspecJve ¡

h1p://jsperf.com/dom-­‑touch-­‑concat ¡ ¡

slide-51
SLIDE 51

DOMland ¡ ECMAland ¡

slide-52
SLIDE 52

DOM ¡

  • caching ¡DOM ¡references ¡
  • caching ¡length ¡in ¡collecJon ¡loops ¡
  • "offline" ¡changes ¡in ¡document ¡fragment ¡
  • batch ¡style ¡changes ¡
  • reducing ¡reflows ¡and ¡repaints ¡
slide-53
SLIDE 53

reflows ¡

bodystyle.color ¡= ¡'red'; ¡ tmp ¡= ¡computed.backgroundColor; ¡ bodystyle.color ¡= ¡'white'; ¡ tmp ¡= ¡computed.backgroundImage; ¡ bodystyle.color ¡= ¡'green'; ¡ tmp ¡= ¡computed.backgroundAttachment; ¡ ¡ bodystyle.color ¡= ¡'red'; ¡ bodystyle.color ¡= ¡'white'; ¡ bodystyle.color ¡= ¡'green'; ¡ tmp ¡= ¡computed.backgroundColor; ¡ tmp ¡= ¡computed.backgroundImage; ¡ tmp ¡= ¡computed.backgroundAttachment; ¡ ¡ ¡getComputedStyle(), ¡or ¡currentStyle ¡in ¡IE ¡

slide-54
SLIDE 54

querySelectorSlow()? ¡

<table ¡border="1" ¡id="test-­‑table"> ¡ ¡ ¡<thead> ¡ ¡ ¡ ¡<!-­‑-­‑ ¡... ¡-­‑-­‑> ¡ ¡ ¡</thead> ¡ ¡ ¡<tbody> ¡ ¡ ¡ ¡ ¡<tr ¡class="rowme"> ¡ ¡ ¡ ¡ ¡ ¡ ¡<td>1</td><td>John</td><td><!-­‑-­‑ ¡... ¡-­‑-­‑> ¡ ¡ ¡ ¡ ¡ ¡ ¡<!-­‑-­‑ ¡... ¡-­‑-­‑> ¡

slide-55
SLIDE 55

querySelectorSlow()? ¡

var ¡trs ¡= ¡ ¡ ¡ ¡tbody.getElementsByClassName('rowme'); ¡ ¡ var ¡trs ¡= ¡ ¡ ¡ ¡tbody.getElementsByTagName('tr'); ¡ ¡ var ¡trs ¡= ¡ ¡ ¡ ¡tbody.querySelectorAll('.rowme'); ¡

slide-56
SLIDE 56

http://jsperf.com/queryinging/4 ¡ ¡

slide-57
SLIDE 57

querySelectorSlow()? ¡

for ¡( ¡ ¡ ¡var ¡i ¡= ¡0, ¡len ¡= ¡trs.length; ¡ ¡ ¡i ¡< ¡len; ¡ ¡ ¡i ¡+= ¡2) ¡{ ¡ ¡ ¡ ¡trs[i].className; ¡ ¡ } ¡

slide-58
SLIDE 58

http://jsperf.com/queryinging/3 ¡ ¡ ¡

slide-59
SLIDE 59

querySelectorSlow()? ¡

for ¡( ¡ ¡ ¡var ¡i ¡= ¡0, ¡len ¡= ¡trs.length; ¡ ¡ ¡i ¡< ¡len; ¡ ¡ ¡i ¡+= ¡2) ¡{ ¡ ¡ ¡ ¡trs[i].className ¡= ¡"rowme ¡hilite"; ¡ ¡ } ¡

slide-60
SLIDE 60

http://jsperf.com/queryinging/2 ¡

slide-61
SLIDE 61

querySelectorSlow()? ¡

for ¡( ¡ ¡ ¡var ¡i ¡= ¡0, ¡len ¡= ¡trs.length; ¡ ¡ ¡i ¡< ¡len; ¡ ¡ ¡i ¡+= ¡2) ¡{ ¡ ¡ ¡ ¡trs[i].className ¡= ¡"rowme ¡hilite"; ¡ } ¡ trs[0].offsetHeight; ¡

slide-62
SLIDE 62

http://jsperf.com/queryinging/ ¡ ¡

slide-63
SLIDE 63

PrioriJes ¡

  • 1. Loading ¡– ¡drop ¡everything, ¡fix ¡now ¡
  • 2. Reflows ¡– ¡fix ¡asap ¡
  • 3. WriJng ¡DOM ¡
  • 4. Reading ¡DOM ¡
  • 5. Querying ¡DOM ¡
  • 6. ECMALand ¡-­‑ ¡later ¡
slide-64
SLIDE 64

data ¡a1ributes ¡

<div ¡data-­‑stuff="convenient"></div> ¡ ¡

  • div.dataset.stuff ¡
  • div.getAttribute('data-­‑stuff') ¡
  • Data.get(div).stuff ¡// ¡DIY ¡
slide-65
SLIDE 65

data ¡a1ributes ¡DIY ¡

var ¡Data ¡= ¡function() ¡{ ¡ ¡ ¡var ¡warehouse ¡= ¡{}; ¡ ¡ ¡var ¡count ¡= ¡1; ¡ ¡ ¡return ¡{ ¡ ¡ ¡ ¡ ¡set: ¡function ¡(dom, ¡data) ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡if ¡(!dom.__data) ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡ ¡dom.__data ¡= ¡"hello" ¡+ ¡count++; ¡ ¡ ¡ ¡ ¡ ¡ ¡} ¡ ¡ ¡ ¡ ¡ ¡ ¡warehouse[dom.__data] ¡= ¡data; ¡ ¡ ¡ ¡ ¡}, ¡ ¡ ¡ ¡ ¡get: ¡function(dom) ¡{ ¡ ¡ ¡ ¡ ¡ ¡ ¡return ¡warehouse[dom.__data]; ¡ ¡ ¡ ¡ ¡} ¡ ¡ ¡}; ¡ }(); ¡

slide-66
SLIDE 66

data ¡a1ributes ¡

slide-67
SLIDE 67

data ¡a1ributes ¡

h1p://jsperf.com/data-­‑dataset ¡ ¡

slide-68
SLIDE 68

Shims ¡and ¡polyfills ¡

slide-69
SLIDE 69

Shims ¡

  • pick ¡the ¡smaller/opJmized ¡one ¡
  • one ¡that ¡uses ¡naJve ¡where ¡available ¡* ¡
  • load ¡condiJonally ¡

e.g. ¡JSON ¡is ¡non-­‑naJve ¡only ¡for ¡8% ¡of ¡users ¡*, ¡ why ¡load ¡shim ¡100% ¡of ¡the ¡Jme ¡

* ¡h1p://html5please.us ¡ ¡ ¡

slide-70
SLIDE 70

Fast ¡ECMAScript5 ¡naJves? ¡

  • JDD: ¡"browsers ¡opJmize ¡loops ¡because ¡of ¡

benchmarks" ¡

  • h1p://jsperf.com/naJve-­‑for-­‑loop-­‑vs-­‑array-­‑

foreach-­‑and-­‑array-­‑map-­‑vs-­‑lodas/2 ¡ ¡ ¡

slide-71
SLIDE 71

jQuery: ¡the ¡most ¡popular ¡polyfill ¡

  • not ¡free ¡(perf-­‑wise) ¡
  • do ¡you ¡need ¡it? ¡
slide-72
SLIDE 72

Cost ¡of ¡parsing ¡and ¡evaluaJng ¡

h1p://calendar.perfplanet.com/2011/ lazy-­‑evaluaJon-­‑of-­‑commonjs-­‑modules/ ¡ ¡

slide-73
SLIDE 73

Cost ¡of ¡parsing ¡and ¡evaluaJng ¡

slide-74
SLIDE 74

Experiment: ¡jQuery ¡vs. ¡Zepto ¡

What’s ¡the ¡cost ¡of ¡just ¡dropping ¡it ¡on ¡the ¡page? ¡

slide-75
SLIDE 75

jsperf.com/zepto-­‑jq-­‑eval ¡

[…] ¡

slide-76
SLIDE 76

jsperf.com/zepto-­‑jq-­‑eval ¡

slide-77
SLIDE 77

jsperf.com/zepto-­‑jq-­‑eval ¡

slide-78
SLIDE 78

In ¡closure… ¡

  • JS ¡off ¡the ¡criJcal ¡path ¡ ¡

(async, ¡lazy, ¡preload) ¡

  • PracJce ¡wriJng ¡jsperf.com ¡tests ¡ ¡

("jsperf ¡URL ¡or ¡it ¡didn't ¡happen!") ¡

  • Don't ¡touch ¡the ¡DOM ¡(remember ¡the ¡bridge) ¡
  • Use ¡the ¡tools ¡(Timeline, ¡CPU/heap ¡profiler, ¡

SpeedTracer, ¡Dynatrace) ¡

  • Think ¡of ¡poor ¡mobile ¡ ¡

(easy ¡with ¡the ¡shims) ¡

slide-79
SLIDE 79

Thank ¡you! ¡

h1p://slideshare.net/stoyan/ ¡