• louis vuitton outlet
  • nike air max
  • ray ban uk
  • oakley sunglasses outlet
  • cheap jordan shoes
  • toms outlet
  • Cheap Oakleys Sunglasses
  • fifa coins
  • ray ban
  • cheap uggs
  • ray ban uk
  • nike air max
  • ray ban outlet
  • burberry uk
  • fut coins
  • fut 14 coins
  • fut coins
  • Christian Louboutin Outlet
  • michael kors outlet
  • coach outlet
  • louis vuitton outlet
  • fifa coins
  • ray ban
  • Custom iphone cases
  • nike
  • monster beats
  • nike outlet
  • Christian Louboutin Outlet
  • burberry outlet
  • coach outlet
  • iphone cases
  • LV
  • new balance
  • Fork/Join in JavaScript

    Fork/Join in JavaScript

    On March 22, 2012, in Patterns, by Alex

    Imagine you have several asynchronous calls that you need to make and you need to delay the execution of some task(s) until after all of the calls have completed.

    Two of my OSS projects, anvil.js and cartographer.js, each deal with this use case in cascading situations. It's been "fun" coming up with ways to solve those in a re-usable manner and I thought I'd share a little bit about the learning experience.

    TL;DR?

    There really isn't one for this post, but let me tell you what I'm going to tell you. First I'll briefly describe Fork/Join, look at a simple implementation and use case. Then I'll show how partial application can take complex calls and reduce the arity requirement to fit with our existing forkJoin call. To end it, I'll create a slightly more realistic example that's more in-line with real-world uses of the pattern.

    Fork/Join

    In languages/runtimes where parallel execution is possible, the fork/join pattern provides your program with the ability to spin up multiple threads/processes to perform the work simultaneously1 while either blocking execution or not invoking some callback until all work has completed.

    In JavaScript, while you can model concurrency, you don't have true parallelism2 and there is no way to block the main line of execution while other code runs. Instead what you can do is make several asynchronous calls and then invoke a callback once all of them have completed.

    Plain English:
    The problem we're solving for is how to delay execution until after several asynchronous calls have completed.

    Simple Implementation

    
        var forkJoin = function( queue, onComplete ) {
            var results = [],
                count = 0,
                i = 0,
                done = function( result ) {
                    if( result != undefined ) {
                        results.push( result );
                    }
                    if( --count === 0 ) {
                        onComplete( results );
                    }
                };
        
            if( queue == undefined || queue.length === 0 ) {
                onComplete( [] );
            } else {    
                count = queue.length;
                for( i = 0; i < queue.length; i++ ) {
                    queue[ i ]( done );            
                }
            }
        };
    

    Explanation

    The queue is a list of functions which take a callback to invoke with their result when they have completed. The onComplete function is simply the callback to invoke with all the results we collected once all the work has completed.

    The done function is the callback that we will pass into each worker function in the queue. When the worker finishes its task, it will invoke the done function with its result. Every time the done function is invoked, it decrements the count variable which represents the total number of out-standing calls to be completed. If the count reaches 0, then all the tasks have completed and we can invoke the onComplete callback with the results collected from the workers.

    In Action (contrived example)

    
        var call1 = function( onDone ) {
            window.setTimeout( function() { onDone( 1 ); }, 20 );
        };
    
        var call2 = function( onDone ) {
            window.setTimeout( function() { onDone( 2 ); }, 50 );
        };
    
        var call3 = function( onDone ) {
            window.setTimeout( function() { onDone( 3 ); }, 30 );
        };
    
        forkJoin( [ call1, call2, call3 ], function( result ) { 
            console.log( result.toString() );
        } );
    

    This example should print some permutation of the numbers 1, 2 and 3 ( probably 1, 3, 2 ) after about 50 miliseconds. You can see an example of this in the jsFiddle:

    That's all well and good, but it's not terribly practical … yet.

    Making Things A Bit More Interesting (Partial Application)

    Partial application allows us to reduce the number of arguments required (arity) to invoke a function by wrapping the call to the original function with specific argument values inside an outer function that will pass through some subset of arguments to the original call.

    Contrived Partial Function Application

    
        var original = function( one, two, three ) {
            console.log( Array.join( [ one, two, three ], " " ) );
        };
    
        var partial = function( adjective ) { 
            original( "hello", adjective, "world" );
        };
    
        partial("cruel"); // will print "hello cruel world"
    

    Um … What?

    The reason we're looking at this is that the forkJoin function above only knows how to invoke functions with an arity of 1. Using partial function application, we can provide forkJoin with a function of reduced arity and still ensure that our original functions are called with the correct arguments.

    Partial Application In Action

    
        var call = function( value, delay, onDone ) {
            window.setTimeout( function() { onDone( value ); }, delay );
        };
    
        var call1 = function( onDone ) {
            call( 1, 20, onDone );
        };
    
        var call2 = function( onDone ) {
            call( 2, 50, onDone );
        };
    
        var call3 = function( onDone ) {
            call( 3, 30, onDone );
        };
    
        forkJoin( [ call1, call2, call3 ], function( result ) { 
            console.log( result.toString() );
        } );
    

    This produces the same result as the example above. The point here is that we're able to call more complex functions but expose them as a simple function that only takes the callback from forkJoin.

    Let's Get Real

    Up to this point, this post has been a bit dry and academic (but without all the helpful detail and precision you'd expect from a real academic write-up). So let's try and create code that's much closer to something you'd actually encounter and use in a web application.

    Scenario

    I need to make 2 different REST calls to a server API before rendering a response to the page. I only want to render the markup after all the calls have completed. Furthermore, I want to set a timeout on each call so that the request aborts and I get some default result.

    Tools

    I'm going to use jQuery's ajax call for making very simple server requests. The fiddle will use appendTo's mockJax library to intercept the requests and provide responses so that the code actually works without a server. Last, I am using Cartographer to render the results as markup that I can put on the page.

    Code

    
        // perform the actual call
        var request = function( url, limit, fallback, onDone ) {
            $.ajax( {
                url: url,
                timeOut: limit,
                success: function( data ) {
                    onDone( data );
                },
                error: function() {
                    onDone( fallback );
                }
            } );
        };
    
        // create a partial application for the GitHub profile request
        var getGitHubProfile = function( onDone ) {
            request( "http://api.github.com/users/arobson", 
                      1, 
                      {    
                          // content here omitted for brevity
                      },
                    onDone );
        };
    
        // create a partial application for the Twitter profile request
        var getTwitterProfile = function( onDone ) {
            request( "https://api.twitter.com/1/users/show.json?screen_name=A_Robson", 
                      1, 
                      {    
                        // content here omitted for brevity
                      },
                    onDone );
        };
    
        // create a map function for the profile template
        cartographer.map( "profile" );
    
        // make the calls and render a template with the data when all calls are complete
        forkJoin( [ getGitHubProfile, getTwitterProfile ], function( data ) { 
            var profile = $.extend( {}, data[0], data[1] );
            cartographer.render( "profile", "test", profile, function( id, markup, op ) {
                $("#placeholder").hide().fadeIn( 300 ).html( markup );
            } );
        } );

    This is only a portion of what's in the fiddle, but it's the part that really matters. The request function is where the work is actually getting done, but there's not a clean way to provide the arguments from the forkJoin call itself. The solution demonstrated here is to use partial application to reduce the arity for forkJoin.

    Once we've received a response from each request, our callback is invoked with the list of results. These results are then being merged together using jQuery's extend.

    The cartographer lines are creating a template from a DOM element and then rendering markup based on the merged JSON responses from the server.

    Fiddle

    Summary

    I hope this post was interesting. If there are improvements, please make a comment and I'll try to get the source and fiddles on the page updated with thanks and mention of your contribution. I'm certainly not an expert but I've really enjoyed what using this pattern has enabled me to accomplish so far.

    Notes

    1. At least as much as the system will allow given hardware and load constraints
    2. Ok, so you *could* use web-workers or the up-coming stuff in Node but … don't
    
    Tagged with:  
    • http://ifandelse.com Jim Cowart

      I really like that you chose to demonstrate this in plain JavaScript and not post “yet another ‘how to use $.deferred’ blog” as others have done. Aside from the obvious “um, why does your DOM manipulation library also handle deferreds”/”kitchen-sink-fx” kinds of debates that can arise, it’s essential that people using *any* abstraction around deferred style behavior understand what’s actually going on, and this is a very clean and readable example.

    • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1071

    • http://adeelcap15.myid.net/ Adeel

      If I have functions with different paramters, what changes in forkJoin expected?