Skip to content

Instantly share code, notes, and snippets.

@curioussavage
Forked from possibilities/meteor-async.md
Last active August 29, 2015 14:13
Show Gist options
  • Select an option

  • Save curioussavage/e438e819250a2396f16d to your computer and use it in GitHub Desktop.

Select an option

Save curioussavage/e438e819250a2396f16d to your computer and use it in GitHub Desktop.

If you're reading this you probably understand that Meteor's server side code is all run synchronously. This article gives a mini-tour of patterns we can use when we need to run asynchronous code in the Meteor environment

Basic async

Often we want to use a 3rd party library without a synchronous interface or we want to use the asynchronous interface because we're going to run something that could take a very long time to complete and we want to use the unblocking technique (described below) to process additional request for the client while we wait. The basic pattern for this can be found all over Meteor's codebase and looks like this:

Meteor.methods({
  asyncJob: function(message) {
  
    // Setup a future
    var fut = new Future();

    // This should work for any async method
    setTimeout(function() {

      // Return the results
      fut.ret(message + " (delayed for 3 seconds)");

    }, 3 * 1000);

    // Wait for async to finish before returning
    // the result
    return fut.wait();
  }
});

Code

Parallel async

We also commonly need to run multiple async calls in parallel. This could be applied to any async method but here we're using Meteor's own Meteor.http.get's async method signature because it's commonly desirable to run a batch of http calls in parallel and wait for the result (or not wait for the result using the unblocking technique described below).

Meteor.methods({
  parallelAsyncJob: function(message) {

    // We're going to make http get calls to each url
    var urls = [
      'http://google.com',
      'http://news.ycombinator.com'
    ];

    // Keep track of each job in an array
    var futures = _.map(urls, function(url) {

      // Setup a furture for the current job
      var future = new Future();

      // A callback so the job can signal completion
      var onComplete = future.resolver();

      /// Make async http call
      Meteor.http.get(url, function(error, result) {

        // Do whatever you need with the results here!
    
        // Inform the future that we're done with it
        onComplete(error, result);
      });

      // Return the future
      return future;
    });

    Future.wait(futures);
  }
});

Code

If you want to collect results from parallel async jobs you'll have to do a little more work:

*Note: Eager to see a better implementation of this!

Meteor.methods({
  parallelAsyncJob: function(message) {

    // Setup a future
    var fut = new Future();

    var urls = [
      'http://google.com',
      'http://news.ycombinator.com',
      'https://github.com'
    ];

    var urlResults = [];

    var onComplete = function(err, result) {
      urlResults.push(result);

      // Once we've recieved all the results
      // return them
      if (urlResults.length >= urls.length)

        // Return the results
        fut.ret(urlResults);
    };

    // Keep track of each job in an array
    _.each(urls, function(url) {

      /// Make async http call
      Meteor.http.get(url, function(error, result) {

        // Get the title
        var title = getTitle(result);

        // Inform the future that we're done with,
        // it and send the title in place of the 
        // raw result
        onComplete(error, title);
      });

    });

    // Wait for async to finish before returning
    // the result
    return fut.wait();
  }
});

Code

Unblocking Meteor.methods

TODO

TODO

Accessing Meteor's full environment from async calls

TODO

Packaging async node modules

TODO

Abstractions

At this point I'm leaving this purposely unfinished because until I have opportunities to use these techniques more than once, in real apps, I don't want to guess what the right abstractions are. Hopefully people will write awesome smart packages for this stuff and we can find out together what will be most effective and then campaign for our favorites to be be included in core.

Resources

http://stackoverflow.com/a/11510874

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment