Ricky Bobby's World

Post on 06-May-2015

999 views 1 download

Tags:

description

JS Perf and Functional Programming

Transcript of Ricky Bobby's World

Ricky Bobby’s worldA look into the js performance

We’re speed freaks

[dahl]

Perf Paranoia

for loop vs foreach search

13,317,048

4,336,225

for loop vs foreach search

13,317,048

4,336,225

for loop vs foreach search

13,317,048

4,336,225

Speed Maintainability

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

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

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

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)

This is a tiny town…

”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.”

Angels in the outfield

JavaScript is a single threaded, interpreted

language

Meanwhile…

Enter the declarative

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

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

PART 2

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

Loop Fusion

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

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

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

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']

It works for Functors and Monads too!

Shortcut Fusion

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

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

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

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

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

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

It works for Functors and Monads too!

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

})

Memoization

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

})

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

Memoization

Memoization

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

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

Memoization

var pQuery = $.toIO()

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

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

It works for Functors and Monads too!

Parallel code

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

Parallel code

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

Parallel code

add(2, 3, 5)

Parallel code

liftA3(fn, A1, A2, A3)

Parallel code

var longCalc // Int -> Future(Int)

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

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

Parallel code

var hasName // Attrs -> Validation

liftA3(save, hasName, hasEmail, hasPhone)

It works for Functors and Monads too!

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’

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’

Lazy code

Lazy code

It works for Functors and Monads too!

Just a handful

THANKS!@drboolean