8

How to get the client method.call to wait for an asynchronous function to finish? Currently it reaches the end of the function and returns undefined.

Client.js

Meteor.call( 'openSession', sid, function( err, res ) {
    // Return undefined undefined
    console.log( err, res ); 
});

Server.js

Meteor.methods({
    openSession: function( session_id ) {
        util.post('OpenSession', {session: session_id, reset: false }, function( err, res ){
            // return value here with callback?
            session_key = res;
        });
     }
});
Pastor Bones
  • 7,183
  • 3
  • 36
  • 56
  • I think it's not possible to perform asynchronous tasks inside meteor methods from the client. In the server using Fiber could be an option. – Andreas Nov 02 '12 at 09:18

3 Answers3

6

I was able to find the answer in this gist. In order to run asynchronous code from within a method.call you use Futures which forces your function to wait.

    var fut = new Future();
    asyncfunc( data, function( err, res ){
        fut.ret( res );
    });
    return fut.wait();
Pastor Bones
  • 7,183
  • 3
  • 36
  • 56
6

Recent versions of Meteor have provided the undocumented Meteor._wrapAsync function which turns a function with a standard (err, res) callback into a synchronous function, meaning that the current Fiber yields until the callback returns, and then uses Meteor.bindEnvironment to ensure that you retain the current Meteor environment variables (such as Meteor.userId()).

A simple use would be as the following:

asyncFunc = function(arg1, arg2, callback) {
  // callback has the form function (err, res) {}

};

Meteor.methods({
  "callFunc": function() {
     syncFunc = Meteor._wrapAsync(asyncFunc);

     res = syncFunc("foo", "bar"); // Errors will be thrown     
  }
});

You may also need to use function#bind to make sure that asyncFunc is called with the right context before wrapping it. For more information see: https://www.eventedmind.com/tracks/feed-archive/meteor-meteor-wrapasync

Andrew Mao
  • 35,740
  • 23
  • 143
  • 224
0

Update: Sorry, I should have read the question more carefully. It looks like this question was also asked and answered here.

Apart from futures, another pattern to consider might be updating another model with the data returned from the asynchronous call and then subscribing to that model's changes.


From the meteor.call documentation it looks like the the result argument (err, res) of your callback function should contain the output of your openSession function. But you aren't returning any values from your openSession function so the return value is undefined.

You can test this:

Client:

Meteor.call('foo', function(err, res) {
  console.log(res); // undefined
});

Meteor.call('bar', function(err, res) {
  console.log(res); // 'bar'
});

Server:

Meteor.methods({
  foo: function() {
    var foo = 'foo';
  },
  bar: function() {
    var bar = 'bar';
    return bar;
  }
});
Community
  • 1
  • 1
Harry Love
  • 1,920
  • 1
  • 25
  • 25