91
Ricky Bobby’s world A look into the js performance

Ricky Bobby's World

Embed Size (px)

DESCRIPTION

JS Perf and Functional Programming

Citation preview

Page 1: Ricky Bobby's World

Ricky Bobby’s worldA look into the js performance

Page 2: Ricky Bobby's World

We’re speed freaks

Page 3: Ricky Bobby's World
Page 4: Ricky Bobby's World
Page 5: Ricky Bobby's World
Page 6: Ricky Bobby's World
Page 7: Ricky Bobby's World
Page 8: Ricky Bobby's World
Page 9: Ricky Bobby's World
Page 10: Ricky Bobby's World
Page 11: Ricky Bobby's World
Page 12: Ricky Bobby's World
Page 13: Ricky Bobby's World
Page 14: Ricky Bobby's World
Page 15: Ricky Bobby's World
Page 16: Ricky Bobby's World
Page 17: Ricky Bobby's World
Page 18: Ricky Bobby's World
Page 19: Ricky Bobby's World
Page 20: Ricky Bobby's World

[dahl]

Page 21: Ricky Bobby's World
Page 22: Ricky Bobby's World
Page 23: Ricky Bobby's World
Page 24: Ricky Bobby's World

Perf Paranoia

Page 25: Ricky Bobby's World
Page 26: Ricky Bobby's World
Page 27: Ricky Bobby's World
Page 28: Ricky Bobby's World

for loop vs foreach search

13,317,048

4,336,225

Page 29: Ricky Bobby's World

for loop vs foreach search

13,317,048

4,336,225

Page 30: Ricky Bobby's World

for loop vs foreach search

13,317,048

4,336,225

Page 31: Ricky Bobby's World
Page 32: Ricky Bobby's World
Page 33: Ricky Bobby's World
Page 34: Ricky Bobby's World

Speed Maintainability

Page 35: Ricky Bobby's World

var result = []; for(var i=0, len=arr.length; i < len; i++) { result.push(doSomething(arr[i])); }return result;

For loops are faster!

arr.map(doSomething);

Page 36: Ricky Bobby's World

MyFramework.CSSMyFramework.AnimationsMyFramework.HttpMyFramework.Socket

PROPERTY LOOKUPS

"Nesting objects in order to use dot notation is a great way to namespace and organize your code. Unfortunately, when it comes to performance, this can be a bit of a problem." -stoyan

http://www.phpied.com/extreme-javascript-optimization/

MyFramework.Rendering.CSSMyFramework.Rendering.AnimationsMyFramework.Network.HttpMyFramework.Network.Socket

Page 37: Ricky Bobby's World

var Fn1 = 0;var Fn2 = 1;

function nextFibonacci() { var f1 = Fn1, f2 = Fn2, f3 = f1 + f2;

Fn1 = f2; Fn2 = f3; return f3;}

Global Variable Caching

var Fn1 = 0;var Fn2 = 1;

function nextFibonacci() { var ret = Fn1 + Fn2; Fn1 = Fn2; Fn2 = ret; return ret;}

Page 38: Ricky Bobby's World

var iterations = Math.floor(values.length / 8);var leftover = values.length % 8;var i = 0;

if (leftover > 0){ do { process(values[i++]); } while (--leftover > 0);}

do { process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]);} while (--iterations > 0);

Loop unrolling

values.forEach(processData)

Page 39: Ricky Bobby's World

This is a tiny town…

Page 40: Ricky Bobby's World
Page 41: Ricky Bobby's World
Page 42: Ricky Bobby's World
Page 43: Ricky Bobby's World
Page 44: Ricky Bobby's World
Page 45: Ricky Bobby's World

”you are not allowed to care about the performance of * unless you concatenate all your javascript, have it at the bottom, minify your css and js, gzip all your assets, and losslessly compress all your images. If you aren’t getting 90+ Page Speed scores, it’s way too early to be thinking about selector optimization.”

Page 46: Ricky Bobby's World
Page 47: Ricky Bobby's World
Page 48: Ricky Bobby's World

Angels in the outfield

Page 49: Ricky Bobby's World

JavaScript is a single threaded, interpreted

language

Page 50: Ricky Bobby's World
Page 51: Ricky Bobby's World

Meanwhile…

Page 52: Ricky Bobby's World
Page 53: Ricky Bobby's World
Page 54: Ricky Bobby's World
Page 55: Ricky Bobby's World

Enter the declarative

Page 56: Ricky Bobby's World
Page 57: Ricky Bobby's World

var result = []; for(var i=0, len=users.length; i < len; i++) { if(users[i].name.length > 0) { result.push(users[i]); } } return result;

users.filter(function(u){ return u.name.length > 0})

declarative

imperative

Page 58: Ricky Bobby's World

59 // src :: FlickrItem -> URL 60 var src = compose(_.get('m'), _.get('media')); 61 62 // srcs :: FlickrSearch -> [URL] 63 var srcs = compose(map(src), _.get('items')); 64 65 // images :: FlickrSearch -> [DOM] 66 var images = compose(map(imageTag), srcs); 67 68 // tags :: FlickrSearch -> [DOM] 69 var tags = compose(toP, _.countBy(_.identity), _.filter(_.isEmpty), chain(split(' ' 70 71 // imagesAndTags :: Tuple [DOM] [DOM] 72 var imagesAndTags = liftA2(Tuple, images, tags) 73 74 // widget :: String -> PictureBox 75 var widget = compose(PictureBox, map(imagesAndTags), getJSON, url); 76 77 /////////////////////////////////////////////////////////////////////////////////// 78 79 mconcat([widget('cats'), widget('dogs')]).fork(log, function(x){ 80 compose(setHtml($('#flickr')), _.first)(x) 81 compose(setHtml($(‘#tag_cloud')), _.last)(x) 82 }); 83 });

Page 59: Ricky Bobby's World

PART 2

Page 60: Ricky Bobby's World

compose(map(g), map(f)) == map(compose(g, f))

chain(xs).map(f).map(g).value() == chain(xs).map(compose(g, f)).value()

Loop Fusion

Page 61: Ricky Bobby's World

Loop Fusion

var bigFirst = compose(map(first), map(capitalize))

var bigFirst = map(compose(first, capitalize))

bigFirst(['ham', 'cake']) // ['H', 'C']

Page 62: Ricky Bobby's World

Loop Fusion

var bigFirst = function(xs) { return chain(xs).map(capitalize).map(first).value()}

var bigFirst = function(xs) { return chain(xs).map(compose(first, capitalize)).value()}

bigFirst(['ham', 'cake']) // ['H', 'C']

Page 63: Ricky Bobby's World

It works for Functors and Monads too!

Page 64: Ricky Bobby's World

Shortcut Fusion

// g :: forall b. (t -> b -> b) -> b -> b

reduce(c, n, build(g)) = g(c, n)

Page 65: Ricky Bobby's World

Shortcut Fusion

//build :: (forall b. (a -> b -> b) -> b -> b) -> [a]var build = function(g){ return g(concat, []);}

//+ map :: (a -> b) -> [a] -> [b]var map = curry(function(f, xs){ return build(function(c, n){ return reduce(function(acc, x){ return c(f(x), acc); }, n, xs); });});

Page 66: Ricky Bobby's World

Shortcut Fusion

var sum = reduce(add, 0);

var sqr = function(x) {return x * x }

var sumSqs = compose(sum, map(sqr)) // reduce(function(acc, x){ return add(sqr(x), acc) }, 0);

Page 67: Ricky Bobby's World

Shortcut Fusion

var sum = reduce(add, 0);

var sqr = function(x) {return x * x }

var sumSqs = function(xs) { return chain(xs).map(sqr).sum().value()// chain(xs).reduce(function(acc, x){ return add(sqr(x), acc) }, 0).value();}

Page 68: Ricky Bobby's World

Good Producers

• List comprehensions

• concat

• foldr

• map

• take

• filter

• partition

• head

• and, or, any, all

• sequence

• sortBy

• zip

• zipWith

• List comprehensions

• Explicit lists

• cons

• concat

• map

• take

• filter

• iterate, repeat

• repeat

• zip

• zipWith

Good Consumers

Page 69: Ricky Bobby's World

It works for Functors and Monads too!

Page 70: Ricky Bobby's World

var addTwenty = memoize(function(x) {return x + 20;

})

Memoization

Page 71: Ricky Bobby's World

var addTwenty = memoize(function(x) {return x + 20;

})

addTwenty(10) // 30addTwenty(10) // 30 (didn't run)addTwenty(11) // 31

Memoization

Page 72: Ricky Bobby's World

Memoization

var getPosts = memoize(function(id) { return new Future(function(rej, res) { $.getJSON('/posts/'+id, res); });});

Page 73: Ricky Bobby's World

Memoization

var getPosts = memoize(function(id) { return new Future(function(rej, res) { $.getJSON('/posts/'+id, res); });});

getPosts(2) // FuturegetPosts(2) // Future (didn't run)getPosts(3) // Future

Page 74: Ricky Bobby's World

Memoization

var pQuery = $.toIO()

pQuery(".troll") // IO(function(){ return $(".troll") })

pQuery.runIO() // [Dom, Dom]pQuery.runIO() // [Dom, Dom, Dom]

Page 75: Ricky Bobby's World
Page 76: Ricky Bobby's World

It works for Functors and Monads too!

Page 77: Ricky Bobby's World

Parallel code

f(f(x, y), z) == f(x, f(y, z))

Page 78: Ricky Bobby's World

Parallel code

add(add(2, 3), 5) == add(2, add(3, 5))

Page 79: Ricky Bobby's World

Parallel code

add(2, 3, 5)

Page 80: Ricky Bobby's World

Parallel code

liftA3(fn, A1, A2, A3)

Page 81: Ricky Bobby's World

Parallel code

var longCalc // Int -> Future(Int)

var collectResults = curry(function(rslt1, rslt2, rslt3){})

liftA3(collectResults, longCalc(20), longCalc(30), longCalc(10))

Page 82: Ricky Bobby's World

Parallel code

var hasName // Attrs -> Validation

liftA3(save, hasName, hasEmail, hasPhone)

Page 83: Ricky Bobby's World

It works for Functors and Monads too!

Page 84: Ricky Bobby's World

Compile while youcompose

var characters = [ { 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }, { 'name': 'pebbles', 'age': 1 }];

var youngest = _.chain(characters) .sortBy('age') .map(function(chr) { return chr.name + ' is ' + chr.age; }) .first() .value();// → 'pebbles is 1’

Page 85: Ricky Bobby's World

Compile while youcompose

var characters = [ { 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }, { 'name': 'pebbles', 'age': 1 }];

var youngest = _.chain(characters) .sortBy('age') .map(function(chr) { return chr.name + ' is ' + chr.age; }) .first() .value();// → 'pebbles is 1’

Page 86: Ricky Bobby's World

Lazy code

Page 87: Ricky Bobby's World

Lazy code

Page 88: Ricky Bobby's World

It works for Functors and Monads too!

Page 89: Ricky Bobby's World
Page 90: Ricky Bobby's World

Just a handful

Page 91: Ricky Bobby's World

THANKS!@drboolean