This past week I was working on a Meteor project that made use of a Node.js package that used promises; specifically es6-promises. I often found myself wanting to return results from this package in my Meteor method calls. This meant I had to use some form of Fibers/Futures to transform my asynchronous promises into “synchronous” code.
The usual method of transforming asynchronous code into a synchronous style is to use Meteor’s wrapAsync
utility method. wrapAsync
works by wrapping your provided function in a future that returns when the callback to your provided asynchronous function is called. Unfortunately, wrapAsync
only works with traditional asynchronous methods that take an error-first callback as their last parameter. This means we won’t be able to use it to transform our promises into a synchronous style.
Without being able to use wrapAsync
, I found myself writing a lot of code that looked like this:
Meteor.methods({
lolpromises: function(a) {
Future = Npm.require('fibers/future');
var future = new Future();
returnsPromise().then(function(res) {
future.return(res);
}, function(err) {
future.throw(err);
});
return future.wait();
}
});
Basically, I’m creating a Future, and returning what the value of that future will be from the method. My promise resolve
method returns the value to the future, and the reject
method throws the rejected value as an exception.
I decided to wrap this functionality into a package: east5th:wrap-promise. Using that package, you can return a promise in a synchronous styling like this:
Meteor.methods({
lolpromises: function(a) {
return wrapPromise(returnsPromise());
}
});
The package is duck-typing the promise’s then
interface, so it should work with any promise library that supports that interface. Check out the code if you’re interested.
After talking about this with Dean Radcliffe, I realized that there’s a better, officially supported way to accomplish my goal: Promise.await in the promise Meteor package.
Using the core promise package, our lolpromises
method would look like this:
Meteor.methods({
lolpromises: function(a) {
return Promise.await(returnsPromise());
}
});