Guig
Guig

Reputation: 10429

How can I execute a callback on a meteor method that does async calls?

My client is making a call to the server.

Meteor.call('someRequest', params, onAllDoneCallback);

that is processed by (server code)

Meteor.methods({
    'someRequest': function(params, cb) {
        anAsyncFunction(params, cb);
        return true;
    },
});

I'd like the onAllDoneCallback to be triggered on the client side once the anAsyncFunction has finished and triggers its own callback.

However, in Meteor it seems that the second argument of someRequest is ignored and that the onAllDoneCallback is triggered with what someRequest returns, which here is true and which is called before that anAsyncFunction has finished.

In my case I'm more concerned about the timing issue (I'm using it to tell the client that the processing is finished, and not just that the request is well received) but other will probably want to call the callback with arguments from anAsyncFunction

Upvotes: 5

Views: 2959

Answers (2)

Guig
Guig

Reputation: 10429

adapting this answer: Meteor: Proper use of Meteor.wrapAsync on server

You have to use Meteor's wrapAsync api, which takes a function that accepts a callback as its last argument, the callback being like function(error, result){}. So it will look like:

Meteor.methods({
    'someRequest': function(params){
        var wrap = Meteor.wrapAsync(anAsyncFunction);
        return wrap(params);
    },
});

Upvotes: 0

corvid
corvid

Reputation: 11197

What you are doing now is passing a function to the server. If that does work, it's very insecure. What you want to do is create a future and then use it to manage the asynchronous function. Here is an example:

let Future = Npm.require('fibers/future');
Meteor.methods({
  someRequest: function (someArg) {
    // for security reasons, make sure you check the type of arguments.
    check(someArg, String);

    // future is an async handler.
    let future = new Future();
    // this is a function for a generic node style callback [ie, function (err, res)]
    let resolver = future.resolver();

    // run your function and pass it the future resolver
    // the future will be resolved when the callback happens.
    anAsyncFunction(someArg, resolver);

    // this meteor method will not end until future has been resolved.
    return future.wait();
  }
});

Alternatively, Meteor provides a wrapAsync that provides similar functionality of wrapping async functions in futures so they can run in meteor methods. That is:

let wrappedAsyncFunction = Meteor.wrapAsync(anAsyncFunction /** second argument is `this` binding*/);
return wrappedAsyncFunction();

Upvotes: 4

Related Questions