Meteor: Using synchronous libraries – wrapAsync and bindEnvironment

Meteor: Using synchronous libraries – wrapAsync and bindEnvironment

By February 23, 2017Engineering

###Whats Meteor.wrapAsync and Meteor.bindEnvironment?

In Part 1, we saw how Meteor abstracted asynchronous code using Fibers and provided an easy way to write JS in a synchronous style. In part 2 we understand how to work with pure asynchronous libraries

Using Fibers we can modify an asynchronous function, to write synchronous like code. However, what happens when we cannot modify the function as in the case of third party libraries?

At ShareThis, our Meteor application uses Amazon’s S3 as a cache and data storage layer. From Amazon S3 documentation, the JavaScript method signature to add to an S3 bucket looks like

“`

getObject(params = {}, callback) ⇒ AWS.Request

//This is how the function would look in Meteor server code

    S3.putObject({

    Bucket: ‘sharethis-insights-store’,

    Key : key,

    Body : data

    }, function(err, result){

    if(result){

      console.log(“Done”);

      //optionally pass in callback

    }

    });

“`

The above code will not work as expected, as the callback to S3.putObject is not bound to the current Fiber

In this use case, we use Meteor.wrapAsync and  to wrap the asynchronous function into the current Fiber

###What does Meteor.wrapAsync do?

Meteor.wrapAsync takes in the method you give it as the first parameter and runs it in the current fiber.

It also attaches a callback to it (it assumes the traditional node style of using a callback, that is the method takes a callback as its final parameter with two arguments(error and result)of which either one will be null depending on the result of the call

The callback is bound with Meteor.bindEnvironment and blocks the current Fiber until the callback is fired. As soon as the callback fires it returns the result or throws the error.

”`javascript

function synchronousFunc(){

return Meteor.wrapAsync(asyncFunction)

}

“`

**How do we access the error object using the synchronous wrapped functions returned by Meteor.wrapAsync ?**

One method is using try/catch blocks, because in case of error, it will be thrown by the sync function instead of being passed as first argument of the async function callback.

”`

try{

var result=synchronousFunc(params);

console.log(“Success :”,result);

}

catch(error){

console.log(“Error:”,error);

}

// which is equivalent to –

asyncFunction(params,function(error,result){

if(error)

    console.log(“error”,error);

else

    console.log(“result :”,result);

});

“`

This is great for converting asynchronous code into synchronous code since you can use the result of the method on the next line instead of using a callback and/or nesting deeper functions. It even takes care of binding the callback to the current Fiber (using Meteor.bindEnvironment) for you.

One last note, if you want the callback to the asynchronous library function to do something more (just because) you have to use Meteor.bindEnvironment explicitly or else you get an error stating that Meteor code must always run within a Fiber.

”`

var func = function(cb){

    S3.putObject(params, Meteor.bindEnvironment(function(err, data) {

      if (err){

       throw new Meteor.Error(“Storage on S3 Failed”);

      } else{

        console.log(“Successfully stored data on S3”);

          cb(null, data);

    }

    }));

 };

return (Meteor.wrapAsync(func))();

“`

Few Gotchas that you need to be aware of when using Meteor.wrapAsync

It is meant to work with pure async functions that expect a callback with error and result as arguments. Also, they only work on the server-side (since you cannot use Fibers on the client-side)

Server-side methods such as Meteor.HTTP.call are already wrapped this way. If you call it without a callback, the method will block until the response is received. Otherwise, it will return immediately and then execute the callback once the network response is received.

About ShareThis

ShareThis has unlocked the power of global digital behavior by synthesizing social share, interest, and intent data since 2007. Powered by consumer behavior on over three million global domains, ShareThis observes real-time actions from real people on real digital destinations.

Subscribe to our Newsletter

Get the latest news, tips, and updates

Subscribe

Related Content