Practical Functional Javascript

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    10 Favorites

    Practical Functional Javascript - Presentation Transcript

    1. Practical Functional JavaScript Oliver Steele Ajax Experience Wednesday, 1 October 2008
    2. Teasers • AJAX is all about waiting for someone*, and remembering what you were going to do when they got back to you. • Functions : interactions :: objects : domains • You didn't really want threads anyway. (Most of the time.) * user, web server, other server, wall clock, plugin
    3. About Me implementing using where? what? graphics languages graphics languages Ruby bindings for “Minority Oblong Industries Report”-style interfaces ✔ ✔ BrowseGoods Entrepreneurial & Style&Share Consulting Fansnap ✔ ✔ Webtop Calendar Laszlo Systems OpenLaszlo ✔ ✔ Apple Advanced Dylan ✔ ✔ Technology Group (programming language) Apple System Software Skia ✔ ✔ (graphics library)
    4. About You Raise your hand if you know*: • Closures • Ruby / Smalltalk • XHR / AJAX • An AJAX framework (Prototype / jQuery / …) • Threads * none of these are required; this just helps me calibrate the talk
    5. Agenda • Context • Callbacks • Example Applications • Queueing & Throttling • MVC on the Client • Caching & Joining • Retries & Failover • Fundamentals • Closures (review) • Conclusions • Making Functions • Decorating Functions • Q&A • Some Idioms
    6. Non-Agenda • Comet, Bayeux, Gears • Frameworks* • Theory (this isn't your Monad or CPS fix) • Security (standard practices apply) * This talk should help you understand their implementation and use, but doesn't explore their APIs in any depth
    7. Example Applications
    8. BrowseGoods • Visually browse an Amazon department, graphically arranged • Server: Ruby (layout, image processing, app server) • Client: Prototype + Scriptaculous
    9. BrowseGoods Capabilities • Background prefetch of item maps • Background fetch of saved items • Operations on saved items are queued until initialization is complete
    10. Style & Share Server Architecture Client Internet Web Application Processes Catalog Cart Image Controller Controller Controller Catalog Model Product Image Request Catalog Carts Images Request Queue Queue Catalog Image Editor Updater Cart Sweeper Image ECS Client Retriever Catalog Update Process Garbage Collector Image Process Client Architecture Internet Catalog Cart Manager Search Gallery ECS Cart Server Cart Selector ECS Search Amazon ECS Amazon Image Proxy Proxy Server Servers ECS Connection Server Proxy AJAX Throttle Task Scheduler Internet ECS Server Style&Share Server
    11. Style & Share Capabilities • Retry with exponential backoff and failover • Explicit queues to control serialization order • Background prefetch for catalog items • Multiple queues to prioritize user interaction
    12. Fansnap • Visualize available seats in a venue • Seatmap is OpenLaszlo (compiled to Flash) • Widgets are in jQuery
    13. FanSnap Capabilities (Seatmap) • Two-way asynchronous communication between the Flash plugin and the HTML • Asynchronous communication between the Flash plugin and the server • Again, initialization is particularly challenging
    14. Webtop Calendar Webtop Calendar Client Data Architecture Calendar Client View Layer Event Event Model Calendar Model Observer Data Layer Event Calendar Calendar Service Cache Collection Range Event Report Cache Cache Serializer CalendarConnection Webtop Client Library Internet Webtop Server
    15. Webtop Calendar Capabilities (Data Model) • Synchronizes local model with server model • Local model is cache: some operations update it; others invalidate it • Race conditions, where prefetch overlaps operations that invalidate the cache
    16. Motivating Problem: Web MVC Server Client View View Model Model User Controller Controller
    17. MVC Basics
    18. Server: Waiting on the Client Server Client View Model User Controller
    19. Client: Waiting on the Server Server Client View Model Model Controller
    20. Client: Waiting on the User Client View Model User Controller
    21. Lots of Waiting • Client (server session) • Server (XHR) • Concurrency • User (UI event) • State • Future (setTimeout)
    22. Function Fundamentals
    23. What is a Function? Create Call graph • Math: rule that maps inputs to outputs Invoke Docs • Computer science: abstracted computation Specs with effects and outputs • Source Runtime Software engineering: one of several units Register forCode Object documentation, testing, assertions, and Def’n analysis • Source code: unit of source text with Store inputs and outputs Contract Implementation • Runtime: invocable parameterized behavior Pass
    24. Nested Functions: Globals function callback(x) { log('received \"' + x + '\"'); }   function request() { $.get('/request', callback); }   request();    
    25. Nested Functions: Variables var callback = function(x) { log('received \"' + x + '\"'); }   var request = function() { $.get('/request', callback); }   request();    
    26. Nested Functions: Function-First Style function request() { function callback(x) { log('received \"' + x + '\"'); } $.get('/request', callback); }   request();    
    27. Nested Functions: Pyramid Order function request() { $.get('/request', callback); function callback(x) { log('received \"' + x + '\"'); } }   request();    
    28. Nested Functions: Inlining the Function function request() { $.get('/request', function callback(x) { log('received \"' + x + '\"'); }); }   request();    
    29. Nested Functions: Anonymous function request() { $.get('/request', function (x) { log('received \"' + x + '\"'); }); }   request();  
    30. Creating Functions: Basics function makeConst1() { return function() { return 1; } }   function const1a() { return 1; } var const1b = function() { return 1; } var const1c = makeConst1();   log(const1a()); log(const1b()); log(const1c());   log(makeConst1()());    
    31. Creating Functions: Variable Capture function makeConstN(n) { return function() { return n; } }   var const10 = makeConstN(10); log(const10()); log(const10(100));   var const20 = makeConstN(20); log(const20()); log(const20(100));    
    32. Creating Functions: Capturing More Variables function makePlus1() { return function(x) { return x + 1; } } log(makePlus1()(10)); function makePlusN(n) { return function(x) { return x + n; } } var plus10 = makePlusN(10); log(plus10(100));      
    33. Creating Functions: Function-Valued Parameters function plus1(x) { return x+1; }   function twice(fn) { return function(x) { return fn(fn(x)); } }   var plus2 = twice(plus1); log(plus2(10));    
    34. Creating Functions: Storage var FnTable = { '+1': function(n) { return n+1; }, '+2': function(n) { return n+2; } };   log(FnTable['+1'](10)); log(FnTable['+2'](10));    
    35. Creating Functions: Building a Registry var FnTable = {}; function register(name, fn) { FnTable[name] = fn; } function tableMethod(name) { return FnTable[name]; } function makeAdder(n) { return function(x) { return x + n; } }   register('+1', makeAdder(1)); register('+2', makeAdder(2)); log(tableMethod('+1')(10)); log(tableMethod('+2')(10));    
    36. Creating Functions: Manual Guards for (var i = -5; i < 5; i++) log(i);     function callIfPositive(fn) { return function(x) { return x > 0 ? fn(x) : undefined; } }   var logIfPositive = callIfPositive(log);   for (var i = -5; i < 5; i++) logIfPositive(i);    
    37. Creating Functions: Guard Construction function guard(fn, g) { return function(x) { return g(x) ? fn(x) : undefined; } }   function callIfPositive(fn) { return guard(fn, function(x) { return x > 0; }); }   var logIfPositive = callIfPositive(log);   for (var i = -5; i < 5; i++) logIfPositive(i);  
    38. Closures (1) var get, set; function assignAccessors() { var x = 1; get = function() { return x; } set = function(y) { x = y; } } assignAccessors(); log(get()); set(10); log(get());
    39. Closures (2) function makeAccessors() { var x; return {get: function() { return x; }, set: function(y) { x = y; }} } var gf1 = makeAccessors(); var gf2 = makeAccessors(); gf1.set(10); gf2.set(20); log(gf1.get()); log(gf2.get());  
    40. Function Construction Idioms: Special Variables // 'this' and 'arguments' are special function f() { logArguments(this, arguments); } f(); f('a'); f('a', 'b');    
    41. Function Construction Idioms: Function Call and Apply function f() { logArguments(this, arguments); } // these are equivalent: f(1, 2, 3); f.call(window, 1, 2, 3); f.apply(window, [1, 2, 3]);    
    42. Function Construction Idioms: Method Call and Apply var obj = { f: function() { logArguments(this, arguments); }}; // and so are these: obj.f(1, 2, 3); obj.f.call(obj, 1, 2, 3); obj.f.apply(obj, [1, 2, 3]);
    43. Function Construction Idioms: Borrowing Methods (Bad) // stealing a method the wrong way var o1 = {name: 'o1', show: function() { log(this.name); }}; var o2 = {name: 'o2'}; o1.show(); o2.show = o1.show; o2.show(); delete o2.show;    
    44. Function Construction Idioms: Borrowing Methods (Better) // using 'apply' to steal a method var o1 = {name: 'o1', show: function() { log(this.name); }}; var o2 = {name: 'o2'}; o1.show(); o1.show.call(o2); o1.show.apply(o2, []);  
    45. Function Construction Idioms: arguments is special // arguments isn't an Array, so this doesn't work: function capture() { var args = arguments.slice(0); // ... }   // instead, steal the 'slice' method from an instance of Array, // and apply it: function capture() { var args = [].slice.call(arguments, 0); // ... }   // or just take it from Array's prototype function capture() { var args = Array.prototype.slice.call(arguments, 0); // ... } 
    46. Function Construction Idioms: Wrapping Variadic Functions function id1(fn) { return function(x) { return fn(x); } }   function id2(fn) { return function(x, y) { return fn(x, y); } }   function idn(fn) { return function() { return fn.apply(this, arguments); } }
    47. Function Construction Idioms: Record and Replay var queue = []; function capture() { queue.push(Array.prototype.slice.call(arguments, 0)); } function replay() { while (queue.length) fn.apply(null, queue.shift()); } function fn(a, b) { log(a + ' + ' + b + ' = ' + (a+b)); } capture(1,2); capture(1,3); capture(10,20); replay();
    48. Function Construction Idioms: Extending Function’s Prototype Function.prototype.twice = function() { var fn = this; return function() { return fn.call(this, fn.apply(this, arguments)); }; } function plus1(x) { return x+1; } var plus2 = plus1.twice(); log(plus2(10));  
    49. Summary • Functions are values • Functions can be arguments, return values, array elements, property values • Functions can be created and “modified” • Argument lists can be saved, modified, and replayed
    50. Case Study: Callbacks Server Client <%@page <html> <?= t <meta <canvas <text <view <?xml v <%@ tag <xslt:t XML <?xml <root> <row> </row> <?xml <root> <row> </row> <?xml v <%@ tag XML <xslt:t <?xml <root> <row> </row>
    51. Callback Scenarii • Chained Callbacks • Conjunctive-Trigger Callbacks • Queues and Priority • Conditional Callbacks • Throttling • Outdated Responses • Caching • Timeouts • Retry and Failover
    52. Throttling: Unthrottled for (var i = 0; i < 10; i++) $.get('/services/time', log);    
    53. Frequency Throttling: Call Site var gCounter = 0; function runNext() { if (gCounter < 10) { setTimeout(function() { $.get('/services/time', log); runNext(); }, 1000); gCounter++; } } runNext();    
    54. Frequency Throttling: Manual Wrapper var gQueue = []; var gNextTime = 0; $.throttled = function(url, k) { gQueue.push([url, k]); if (gQueue.length == 1) schedule(); function schedule() { setTimeout(function() { gNextTime = new Date().getTime() + 1000; var entry = gQueue.shift(); $.get(entry[0], entry[1]); if (gQueue.length) schedule(); }, Math.max(0, gNextTime - new Date().getTime())); } };  for (var i = 0; i < 10; i++)   $.throttled('/services/time', log);
    55. Frequency Throttling: Function Constructor function makeThrottled(fn, interval) { var queue = []; var nextTime = 0; return function() { queue.push(Array.prototype.slice.call(arguments, 0)); if (queue.length == 1) schedule(); } function schedule() { setTimeout(function() { nextTime = new Date().getTime() + interval; fn.apply(null, queue.shift()); if (queue.length) schedule(); }, Math.max(0, nextTime - new Date().getTime())); } } $.throttled = makeThrottled($.get, 1000); for (var i = 0; i < 10; i++) $.throttled('/services/time', log);    
    56. Count Throttling: Manual Wrapper var gQueue = []; var gOutstanding = 0; $.throttled = function(url, k) { function k2() { gOutstanding--; k.apply(this, arguments); if (gOutstanding < 2 && gQueue.length) { var entry = gQueue.shift(); $.get(entry[0], entry[1]); } } if (gOutstanding < 2) { gOutstanding++; $.get(url, k2); } else gQueue.push([url, k2]); }; for (var i = 0; i < 10; i++) $.throttled('/services/sleep/2', log);    
    57. Count Throttling: Constructor function makeLimited(fn, count) { var queue = []; var outstanding = 0; return function() { var args = Array.prototype.slice.call(arguments, 0); // replace the last arg by one that runs the // next queued fn args.push(adviseAfter(args.pop(), next)); if (outstanding < count) { outstanding++; fn.apply(this, args); } else queue.push(args); } function next() { if (queue.length) fn.apply(null, queue.shift()); } } $.throttled = makeLimited($.get, 2); for (var i = 0; i < 10; i++) $.throttled('/services/sleep/2', log);
    58. Frequency Throttling: Function Constructor function makeThrottled(fn, interval) { var queue = []; var nextTime = 0; return function() { queue.push(Array.prototype.slice.call(arguments, 0)); if (queue.length == 1) schedule(); } function schedule() { setTimeout(function() { nextTime = new Date().getTime() + interval; fn.apply(null, queue.shift()); if (queue.length) schedule(); }, Math.max(0, nextTime - new Date().getTime())); } } $.throttled = makeThrottled($.get, 1000); for (var i = 0; i < 10; i++) $.throttled('/services/time', log);    
    59. Retry $.getWithRetry = function(url, k) { var countdown = 10; $.ajax({url:url, success:k, error:retry}); function retry() { if (--countdown >= 0) { log('retry'); $.ajax({url:url, success:k, error:retry}); } } }; $.getWithRetry('/services/error', log);    
    60. Throttled Retry var gPageLoadTime = new Date; $.getWithRetry = function(url, k) { var countdown = 10; var delay = 1000; var nextTime = new Date().getTime() + delay; $.ajax({url:url, success:k, error:retry}); function retry() { if (--countdown >= 0) { setTimeout(function() { delay *= 1.5; log('retry@t+' + (new Date - gPageLoadTime)/1000 + 's'); nextTime = new Date().getTime() + delay; $.ajax({url:url, success:k, error:retry}); }, Math.max(0, nextTime - new Date().getTime())); } } }; $.getWithRetry('/services/error', log);
    61. Failover $.getWithFailover = function(urls, k) { $.ajax({url:urls.shift(), success:k, error:retry}); function retry() { if (urls.length) $.ajax({url:urls.shift(), success:k, error:retry}); } }; $.getWithFailover( ['/services/error', '/services/error', '/services/time'], log);  
    62. Caching (1) var gRequestCache = {}; $.cachedGet = function(url, k) { if (url in gRequestCache) k(gRequestCache[url], 'success'); else $.get(url, adviseBefore(k, function(result, status) { if (status == 'success') gRequestCache[url] = result; })); }; $.cachedGet('/services/random', log); $.cachedGet('/services/random', log); $.cachedGet('/services/echo/1', log); $.cachedGet('/services/echo/2', log); setTimeout(function() {$.cachedGet('/services/random', log);}, 1000);    
    63. Caching (2) var gPendingRequests = {}; var gRequestCache = {}; $.cachedGet('/services/random', log); $.cachedGet = function(url, k) { $.cachedGet('/services/random', log); if (url in gRequestCache) $.cachedGet('/services/echo/1', log); $.cachedGet('/services/echo/2', log); k(gRequestCache[url], 'success'); $.cachedGet('/services/random', log); else if (url in gPendingRequests) gPendingRequests[url].push(k); else { var queue = [k]; gPendingRequests[url] = queue; $.get(url, function(result, status) { if (status == 'success') gRequestCache[url] = result; while (queue.length) queue.shift().call(this, result, status); delete gPendingRequests[url]; }); } }; 
    64. Caching (3) function memoizedContinuation(fn) { $.cachedGet('/services/random', log); var cache = {}; return function(key, k) { $.cachedGet('/services/random', log); if (key in cache) $.cachedGet('/services/echo/1', log); k(cache[key]); $.cachedGet('/services/echo/2', log); else $.cachedGet('/services/random', log); fn(key, k);   } } function consolidateContinuations(fn) { var queues = {}; return function(key, k) { if (key in queues) queues[key].push(k); else { var queue = queues[key] = [k]; fn(key, function(value) { while (queue.length) queue.shift().call(this, value); delete queues[key]; }); } } } $.cachedGet = consolidateContinuations(memoizedContinuation($.get));
    65. Summary • Functions-as-objects allow separation of concerns • Factor how, when, and whether from what • Functions are to interaction patterns as objects are to domains
    66. What is FP? • Functions are pure • Functions are values
    67. Q&A
    68. Thanks! – Oliver Steele http://osteele.com

    + Oliver SteeleOliver Steele, 2 years ago

    custom

    9734 views, 10 favs, 5 embeds more stats

    Describes how to use functional programming techniq more

    More info about this presentation

    CC Attribution-NonCommercial LicenseCC Attribution-NonCommercial License

    • Total Views 9734
      • 9691 on SlideShare
      • 43 from embeds
    • Comments 0
    • Favorites 10
    • Downloads 258
    Most viewed embeds
    • 36 views on http://webprogramming.tistory.com
    • 3 views on http://joseanpg.net
    • 2 views on http://techno-sphere.blogspot.com
    • 1 views on http://luisbarriosc.blogspot.com
    • 1 views on http://192.168.10.100

    more

    All embeds
    • 36 views on http://webprogramming.tistory.com
    • 3 views on http://joseanpg.net
    • 2 views on http://techno-sphere.blogspot.com
    • 1 views on http://luisbarriosc.blogspot.com
    • 1 views on http://192.168.10.100

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories