Upload
brian-lonsdorf
View
1.000
Download
1
Embed Size (px)
DESCRIPTION
JS Perf and Functional Programming
Citation preview
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