SlideShare a Scribd company logo
Practical Functional
     JavaScript
         Oliver Steele
       Ajax Experience
   Wednesday, 1 October 2008
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
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)
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
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
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
Example Applications
BrowseGoods
•   Visually browse an
    Amazon department,
    graphically arranged

•   Server: Ruby (layout,
    image processing, app
    server)

•   Client: Prototype +
    Scriptaculous
Practical functional java script
BrowseGoods
         Capabilities

• Background prefetch of item maps
• Background fetch of saved items
• Operations on saved items are queued until
  initialization is complete
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
Practical functional java script
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
Fansnap
•   Visualize available seats
    in a venue

•   Seatmap is OpenLaszlo
    (compiled to Flash)

•   Widgets are in jQuery
Practical functional java script
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
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
Practical functional java script
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
Motivating Problem:
    Web MVC
Server                        Client


                   View                          View


         Model                         Model                User



                 Controller                    Controller
MVC Basics
Server:
Waiting on the Client
    Server                               Client


                       View


             Model                User



                     Controller
Client:
Waiting on the Server
    Server                                Client


                               View


             Model   Model



                             Controller
Client:
Waiting on the User
                          Client


               View


     Model                         User



             Controller
Lots of Waiting
•   Client (server session)

•   Server (XHR)              •   Concurrency

•   User (UI event)           •   State

•   Future (setTimeout)
Function Fundamentals
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
Nested Functions:
         Globals
function callback(x) {
    log('received "' + x + '"');
}
 
function request() {
    $.get('/request', callback);
}
 
request();
 
 
Nested Functions:
         Variables
var callback = function(x) {
    log('received "' + x + '"');
}
 
var request = function() {
    $.get('/request', callback);
}
 
request();
 
 
Nested Functions:
    Function-First Style
function request() {
    function callback(x) {
        log('received "' + x + '"');
    }
    $.get('/request', callback);
}
 
request();
 
 
Nested Functions:
      Pyramid Order
function request() {
    $.get('/request', callback);
    function callback(x) {
        log('received "' + x + '"');
    }
}
 
request();
 
 
Nested Functions:
   Inlining the Function
function request() {
    $.get('/request', function callback(x) {
        log('received "' + x + '"');
    });
}
 
request();
 
 
Nested Functions:
       Anonymous
function request() {
    $.get('/request', function (x) {
        log('received "' + x + '"');
    });
}
 
request();
 
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()());
 
 
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));
 
 
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));
 
 
 
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));
 
 
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));
 
 
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));
 
 
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);
 
 
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);
 
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());
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());
 
Function Construction Idioms:
       Special Variables
// 'this' and 'arguments' are special
function f() {
    logArguments(this, arguments);
}
f();
f('a');
f('a', 'b');
 
 
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]);
 
 
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]);
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;
 
 
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, []);
 
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);
    // ...
} 
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);
    }
}
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();
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));
 
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
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>
Callback Scenarii
•   Chained Callbacks     •   Conjunctive-Trigger
                              Callbacks
•   Queues and Priority
                          •   Conditional Callbacks
•   Throttling
                          •   Outdated Responses
•   Caching

•   Timeouts

•   Retry and Failover
Throttling:
             Unthrottled
for (var i = 0; i < 10; i++)
    $.get('/services/time', log);
 
 
Frequency Throttling:
        Call Site
var gCounter = 0;
function runNext() {
    if (gCounter < 10) {
        setTimeout(function() {
            $.get('/services/time', log);
            runNext();
        }, 1000);
        gCounter++;
    }
}
runNext();
 
 
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);
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);
 
 
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);
 
 
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);
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);
 
 
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);
 
 
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);
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);
 
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);
 
 
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];
        });
    }
}; 
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));
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
What is FP?


• Functions are pure
• Functions are values
Q&A
Thanks!




          – Oliver Steele
      http://osteele.com

More Related Content

PDF
Eu Esri 2011 - Esri (Damian Spangrud)
PDF
Practical Functional Javascript
PPTX
SharePoint 2010 as a Development Platform
PDF
Build Your Business Process On A Solid Foundation–Web Sphere Application Server
PPT
Dreamforce_2012_Hadoop_Use_Cases
PDF
(ATS4-GS02) A Lap Around Accelrys Enterprise Platform and Pipeline Pilot 9.0
PDF
Sakai Technical (Chinese)
PDF
eBay Architecture
Eu Esri 2011 - Esri (Damian Spangrud)
Practical Functional Javascript
SharePoint 2010 as a Development Platform
Build Your Business Process On A Solid Foundation–Web Sphere Application Server
Dreamforce_2012_Hadoop_Use_Cases
(ATS4-GS02) A Lap Around Accelrys Enterprise Platform and Pipeline Pilot 9.0
Sakai Technical (Chinese)
eBay Architecture

Similar to Practical functional java script (20)

PDF
Mobile Monday Silicon Valley June 1st 09 V1
PDF
Implementing Web Commerce In A Complex Environment
PDF
Microsoft Silverlight 2
PDF
Aras Vision and Roadmap with Aras Innovator PLM Software
PPT
Final Academic Project
PDF
API Design & Moving from Junior to Senior Developer
PDF
Siebel CRM: Open UI
PDF
Eva flex java_1_slides
PDF
Mach Technology
PDF
Aras PLM Roadmap
PDF
Building reliable systems from unreliable components
PPTX
6.Live Framework 和Mesh Services
PPTX
Prodware wa college - marcel meijer
PDF
Qcon flex体系架构深度剖析
PDF
Adobe Flex体系架构深度剖析
PPTX
Tech Ed 09 - Arc302 - Analysis and Architecture
PDF
Flex体系架构剖析
PDF
02 Ms Online Identity Session 1
PDF
Ajax World 08 Silverlight2 Overview
PDF
Leadership Symposium on Digital Media in Healthcare
Mobile Monday Silicon Valley June 1st 09 V1
Implementing Web Commerce In A Complex Environment
Microsoft Silverlight 2
Aras Vision and Roadmap with Aras Innovator PLM Software
Final Academic Project
API Design & Moving from Junior to Senior Developer
Siebel CRM: Open UI
Eva flex java_1_slides
Mach Technology
Aras PLM Roadmap
Building reliable systems from unreliable components
6.Live Framework 和Mesh Services
Prodware wa college - marcel meijer
Qcon flex体系架构深度剖析
Adobe Flex体系架构深度剖析
Tech Ed 09 - Arc302 - Analysis and Architecture
Flex体系架构剖析
02 Ms Online Identity Session 1
Ajax World 08 Silverlight2 Overview
Leadership Symposium on Digital Media in Healthcare
Ad

More from thinkphp (14)

PPT
Knut Morris Pratt Algorithm
PPT
String kmp
PPT
String searching
PDF
Functional programming in java script
PDF
Javascript patterns
PDF
Placemaker
ODP
PHP 5.3 And PHP 6 A Look Ahead
PDF
Atom Web Services
PDF
Json Rpc Proxy Generation With Php
PDF
Php And Web Services
PPT
Object Oriented Programming Concepts
PDF
Ajax Introduction Presentation
PPT
PPT
Principii Poo
Knut Morris Pratt Algorithm
String kmp
String searching
Functional programming in java script
Javascript patterns
Placemaker
PHP 5.3 And PHP 6 A Look Ahead
Atom Web Services
Json Rpc Proxy Generation With Php
Php And Web Services
Object Oriented Programming Concepts
Ajax Introduction Presentation
Principii Poo
Ad

Recently uploaded (20)

PPTX
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
PDF
102 student loan defaulters named and shamed – Is someone you know on the list?
PPTX
PPT- ENG7_QUARTER1_LESSON1_WEEK1. IMAGERY -DESCRIPTIONS pptx.pptx
PPTX
Microbial diseases, their pathogenesis and prophylaxis
PDF
2.FourierTransform-ShortQuestionswithAnswers.pdf
PDF
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
PDF
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
PDF
Complications of Minimal Access Surgery at WLH
PDF
O7-L3 Supply Chain Operations - ICLT Program
PDF
Mark Klimek Lecture Notes_240423 revision books _173037.pdf
PDF
TR - Agricultural Crops Production NC III.pdf
PDF
Supply Chain Operations Speaking Notes -ICLT Program
PDF
Physiotherapy_for_Respiratory_and_Cardiac_Problems WEBBER.pdf
PDF
Anesthesia in Laparoscopic Surgery in India
PPTX
Introduction to Child Health Nursing – Unit I | Child Health Nursing I | B.Sc...
PDF
Module 4: Burden of Disease Tutorial Slides S2 2025
PPTX
Cell Types and Its function , kingdom of life
PDF
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
PDF
VCE English Exam - Section C Student Revision Booklet
PDF
FourierSeries-QuestionsWithAnswers(Part-A).pdf
IMMUNITY IMMUNITY refers to protection against infection, and the immune syst...
102 student loan defaulters named and shamed – Is someone you know on the list?
PPT- ENG7_QUARTER1_LESSON1_WEEK1. IMAGERY -DESCRIPTIONS pptx.pptx
Microbial diseases, their pathogenesis and prophylaxis
2.FourierTransform-ShortQuestionswithAnswers.pdf
BÀI TẬP BỔ TRỢ 4 KỸ NĂNG TIẾNG ANH 9 GLOBAL SUCCESS - CẢ NĂM - BÁM SÁT FORM Đ...
ANTIBIOTICS.pptx.pdf………………… xxxxxxxxxxxxx
Complications of Minimal Access Surgery at WLH
O7-L3 Supply Chain Operations - ICLT Program
Mark Klimek Lecture Notes_240423 revision books _173037.pdf
TR - Agricultural Crops Production NC III.pdf
Supply Chain Operations Speaking Notes -ICLT Program
Physiotherapy_for_Respiratory_and_Cardiac_Problems WEBBER.pdf
Anesthesia in Laparoscopic Surgery in India
Introduction to Child Health Nursing – Unit I | Child Health Nursing I | B.Sc...
Module 4: Burden of Disease Tutorial Slides S2 2025
Cell Types and Its function , kingdom of life
Saundersa Comprehensive Review for the NCLEX-RN Examination.pdf
VCE English Exam - Section C Student Revision Booklet
FourierSeries-QuestionsWithAnswers(Part-A).pdf

Practical functional java script

  • 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
  • 8. BrowseGoods • Visually browse an Amazon department, graphically arranged • Server: Ruby (layout, image processing, app server) • Client: Prototype + Scriptaculous
  • 10. BrowseGoods Capabilities • Background prefetch of item maps • Background fetch of saved items • Operations on saved items are queued until initialization is complete
  • 11. 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
  • 13. 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
  • 14. Fansnap • Visualize available seats in a venue • Seatmap is OpenLaszlo (compiled to Flash) • Widgets are in jQuery
  • 16. 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
  • 17. 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
  • 19. 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
  • 20. Motivating Problem: Web MVC Server Client View View Model Model User Controller Controller
  • 22. Server: Waiting on the Client Server Client View Model User Controller
  • 23. Client: Waiting on the Server Server Client View Model Model Controller
  • 24. Client: Waiting on the User Client View Model User Controller
  • 25. Lots of Waiting • Client (server session) • Server (XHR) • Concurrency • User (UI event) • State • Future (setTimeout)
  • 27. 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
  • 28. Nested Functions: Globals function callback(x) { log('received "' + x + '"'); }   function request() { $.get('/request', callback); }   request();    
  • 29. Nested Functions: Variables var callback = function(x) { log('received "' + x + '"'); }   var request = function() { $.get('/request', callback); }   request();    
  • 30. Nested Functions: Function-First Style function request() { function callback(x) { log('received "' + x + '"'); } $.get('/request', callback); }   request();    
  • 31. Nested Functions: Pyramid Order function request() { $.get('/request', callback); function callback(x) { log('received "' + x + '"'); } }   request();    
  • 32. Nested Functions: Inlining the Function function request() { $.get('/request', function callback(x) { log('received "' + x + '"'); }); }   request();    
  • 33. Nested Functions: Anonymous function request() { $.get('/request', function (x) { log('received "' + x + '"'); }); }   request();  
  • 34. 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()());    
  • 35. 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));    
  • 36. 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));      
  • 37. 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));    
  • 38. 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));    
  • 39. 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));    
  • 40. 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);    
  • 41. 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);  
  • 42. 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());
  • 43. 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());  
  • 44. Function Construction Idioms: Special Variables // 'this' and 'arguments' are special function f() { logArguments(this, arguments); } f(); f('a'); f('a', 'b');    
  • 45. 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]);    
  • 46. 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]);
  • 47. 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;    
  • 48. 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, []);  
  • 49. 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); // ... } 
  • 50. 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); } }
  • 51. 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();
  • 52. 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));  
  • 53. 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
  • 54. 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>
  • 55. Callback Scenarii • Chained Callbacks • Conjunctive-Trigger Callbacks • Queues and Priority • Conditional Callbacks • Throttling • Outdated Responses • Caching • Timeouts • Retry and Failover
  • 56. Throttling: Unthrottled for (var i = 0; i < 10; i++) $.get('/services/time', log);    
  • 57. Frequency Throttling: Call Site var gCounter = 0; function runNext() { if (gCounter < 10) { setTimeout(function() { $.get('/services/time', log); runNext(); }, 1000); gCounter++; } } runNext();    
  • 58. 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);
  • 59. 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);    
  • 60. 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);    
  • 61. 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);
  • 62. 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);    
  • 63. 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);    
  • 64. 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);
  • 65. 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);  
  • 66. 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);    
  • 67. 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]; }); } }; 
  • 68. 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));
  • 69. 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
  • 70. What is FP? • Functions are pure • Functions are values
  • 71. Q&A
  • 72. Thanks! – Oliver Steele http://osteele.com