1

I'm trying to call createTableIfNotExists in this npm package, and do so synchronously in Meteor, server-side. https://www.npmjs.com/package/azure-storage

However, the callback signature is of type function(error, result, response) instead of the traditional function(error,result).

1) Because of that, I cannot use Meteor.wrapAsync and instead have to use Meteor.bindEnvironment

2) I call 'bindEnvironment' as below. Note the callback with 3 arguments. This works, but now I would like to extract the return value, back to the original method (i.e. the original fiber).

Note that simply defining 'addResult' outside the createTableService does not work because the callback inside bindEnvironment runs asynchrounously relative to the outside code...i.e. demoFunction() returns before the callback sets addResult.

var demoFunction = function(){
    var addResult = null;
    var tableService = azure.createTableService(acctName, acctKey);
                    tableService.createTableIfNotExists(asTableName, Meteor.bindEnvironment(function(error,result,response){
                        if (error) {
                            throw new Meteor.Error(500, "table create error - " + asTableName + ": "+ error);
                        }
                        console.log(result);
                        if(result){
                            addResult = /*call to meteor method*/ 
                            return addResult;
                        }                   
                    }));

    return addResult; //this is what I would like to do, but will always be null, as written.

}

How can I call createTableIfNotExists and still return addResult back to the function that called demoFunction()?

Thanks!

ASX
  • 635
  • 7
  • 18
  • Using `future` should work. I – Jankapunkt Jan 22 '18 at 22:38
  • thanks - could you please elaborate? I am not familiar at all with ` future` . Looking at this package https://www.npmjs.com/package/fibers but can't figure out how to rework my code above. ====OR==== Is returning a Promise from `demoFunction()` an option as well? I am more familiar with using `async/await` – ASX Jan 22 '18 at 22:46
  • 1
    Sorry for the short answer I am on the run and will try to give you a more detailed answer when I am at home. – Jankapunkt Jan 22 '18 at 22:51
  • 1
    Actually, returning a Promise from `demoFunction`, and then `rejecting/resolving` it inside the bindEnvironment function worked...I did not realize `bindEnvironment` would resolve the outer Promise....although now it makes sense that it carries over the external environment given its name :) =====>>>>> If possible, I'd still like to see a `Future` solution that might enable arbitrary # of asynchrnous calls by creating synchronicity with the `demoFunction()` fiber, as I will probably need it later. – ASX Jan 22 '18 at 23:05

1 Answers1

0

You can use the Future from the fibers/future (node-fibers) package, which is just a different abstraction layer of fibers as this async/await implementation or this promise implementation are, too. (Note, that using a fiber directly is not recommended).

Generic Future pattern

As you already pointed out, you can solve this issue also using async/await or using promises.

However, if you want to know how to use a Future instance, you can follow this popular pattern, which I make use of in many of my applications.

Future pattern with Meteor.bindEnvironment

Including the bindEnvironment into this pattern, and restructuring the code a bit, it looks like the following:

import Future from 'fibers/future';

Meteor.methods({
    myMeteorMethod: function() {
        // load Future
        const myFuture = new Future();

        // create bound callback, that uses the future
        const boundCallback = Meteor.bindEnvironment(function (error,results){
            if(error){
              myFuture.throw(error);
            }else{
              myFuture.return(results);
            }
        });

        // call the function and pass bound callback
        SomeAsynchronousFunction("foo", boundCallback);

        return myFuture.wait();
    }
});

Applied to code example

Applying this modification of the pattern to your code, it could result in something like the code below. Note, that I separated the callback from being created inside the function simply because of readability. You can of course just create it inside the function head, as you typically do.

import Future from 'fibers/future';

var demoFunction = function(){
    // load Future
    const myFuture = new Future();

    // create bound callback, that uses the future
    const boundCallback = Meteor.bindEnvironment(function (error, result, response) {
        if (error) {
            myFuture.throw(new Meteor.Error(500, "table create error - " + asTableName + ": "+ error));
        }

        // do whatever you need to do here
        // with result and response...

        if (result) {
            myFuture.return(result);
        }                   
    });

    var tableService = azure.createTableService(acctName, acctKey);

    // pass the bound callback here
    tableService.createTableIfNotExists(asTableName, boundCallback);

    return myFuture.wait();

}
Jankapunkt
  • 8,128
  • 4
  • 30
  • 59