Ricky Bobby's World

1,480 views

Published on

JS Perf and Functional Programming

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,480
On SlideShare
0
From Embeds
0
Number of Embeds
826
Actions
Shares
0
Downloads
6
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Ricky Bobby's World

  1. 1. Ricky Bobby’s world A look into the js performance
  2. 2. We’re speed freaks
  3. 3. [dahl]
  4. 4. Perf Paranoia
  5. 5. for loop vs foreach search 13,317,048 4,336,225
  6. 6. for loop vs foreach search 13,317,048 4,336,225
  7. 7. for loop vs foreach search 13,317,048 4,336,225
  8. 8. Speed Maintainability
  9. 9. 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);
  10. 10. MyFramework.CSS MyFramework.Animations MyFramework.Http MyFramework.Socket PROPERTY LOOKUPS "Nesting objects in order to use dot notation is a great way to namespace and organize your code. Unfortunately, w http://www.phpied.com/extreme-javascript-optimization/ MyFramework.Rendering.CSS MyFramework.Rendering.Animations MyFramework.Network.Http MyFramework.Network.Socket
  11. 11. 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; }
  12. 12. 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)
  13. 13. This is a tiny town…
  14. 14. ”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.”
  15. 15. Angels in the outfield
  16. 16. JavaScript is a single threaded, interpreted language
  17. 17. Meanwhile…
  18. 18. Enter the declarative
  19. 19. 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
  20. 20. 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 });
  21. 21. PART 2
  22. 22. 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
  23. 23. Loop Fusion var bigFirst = compose(map(first), map(capitalize)) var bigFirst = map(compose(first, capitalize)) bigFirst(['ham', 'cake']) // ['H', 'C']
  24. 24. 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']
  25. 25. It works for Functors and Monads too!
  26. 26. Shortcut Fusion // g :: forall b. (t -> b -> b) -> b -> b reduce(c, n, build(g)) = g(c, n)
  27. 27. 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); }); });
  28. 28. 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);
  29. 29. 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(); }
  30. 30. 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
  31. 31. It works for Functors and Monads too!
  32. 32. var addTwenty = memoize(function(x) { return x + 20; }) Memoization
  33. 33. var addTwenty = memoize(function(x) { return x + 20; }) addTwenty(10) // 30 addTwenty(10) // 30 (didn't run) addTwenty(11) // 31 Memoization
  34. 34. Memoization var getPosts = memoize(function(id) { return new Future(function(rej, res) { $.getJSON('/posts/'+id, res); }); });
  35. 35. Memoization var getPosts = memoize(function(id) { return new Future(function(rej, res) { $.getJSON('/posts/'+id, res); }); }); getPosts(2) // Future getPosts(2) // Future (didn't run) getPosts(3) // Future
  36. 36. Memoization var pQuery = $.toIO() pQuery(".troll") // IO(function(){ return $(".troll") }) pQuery.runIO() // [Dom, Dom] pQuery.runIO() // [Dom, Dom, Dom]
  37. 37. It works for Functors and Monads too!
  38. 38. Parallel code f(f(x, y), z) == f(x, f(y, z))
  39. 39. Parallel code add(add(2, 3), 5) == add(2, add(3, 5))
  40. 40. Parallel code add(2, 3, 5)
  41. 41. Parallel code liftA3(fn, A1, A2, A3)
  42. 42. Parallel code var longCalc // Int -> Future(Int) var collectResults = curry(function(rslt1, rslt2, rslt3){}) liftA3(collectResults, longCalc(20), longCalc(30), longCalc(10))
  43. 43. Parallel code var hasName // Attrs -> Validation liftA3(save, hasName, hasEmail, hasPhone)
  44. 44. It works for Functors and Monads too!
  45. 45. Compile while you compose 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’
  46. 46. Compile while you compose 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’
  47. 47. Lazy code
  48. 48. Lazy code
  49. 49. It works for Functors and Monads too!
  50. 50. Just a handful
  51. 51. THANKS! @drboolean

×