From Meteor's documentation:
In Meteor, your server code runs in a single thread per request, not in the asynchronous callback style typical of Node. We find the linear execution model a better fit for the typical server code in a Meteor application.
This guide serves as a mini-tour of tool, trix and patterns that can be used to run async code in Meteor.
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) {
// Set up 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();
}
});
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) {
// Set up a future 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);
}
});
If you want to collect results from parallel async jobs you'll have to do a little more work:
Meteor.methods({
parallelAsyncJob: function(message) {
var urls = [
'http://google.com',
'http://news.ycombinator.com',
'https://github.com'
];
var futures = _.map(urls, function(url) {
var future = new Future();
var onComplete = future.resolver();
/// Make async http call
Meteor.http.get(url, function(error, result) {
// Get the title if there was no error
var title = (!error) && getTitle(result);
onComplete(error, title);
});
return future;
});
// wait for all futures to finish
Future.wait(futures);
// and grab the results out.
return _.invoke(futures, 'get');
}
});
TODO
TODO
TODO
TODO
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.
Cleanup, writing is terrible
Add all useful info mentioned by Matt here
Thanks to Tom Coleman @tmeasday for his help with this!
This is great. Any chance of this being documented?