meteorBuzz
meteorBuzz

Reputation: 3200

Where is future necessary to run a sequence of async functions in node?

Previously, I have used future.wait() to wait for a value before I return it to the next function. (I am coding in Meteor by the way)

After reading node's non-blocking I/O architecture, doesn't my following method (which does work) defeat the purpose entirely?

What I am doing is passing the returned result from the following 'requesting' function into another function. Instead, is the callback method the best convention?

The only reason why I used future was because using the return gets executed immediately. I want to learn the best practice as I think I am adding extra layers of unnecessary code using future.

If I use the callback convention, callback(null, result), does 'callback' wait for objects to be passed into the arguments?

My code using future to wait for results:

function requesting(perm_data) {
  var f = new future();
  request.get('example.com/api/auth_user', {
    oauth: {consumer_key:'somekey',
            token: perm_data.oauth_token,
            token_secret: perm_data.oauth_token_secret
            }
  }, function response(error, response, body) {
  if (!error && response.statusCode === 200) {
    var bodyToJson = parser.toJson(body, options)
    var userId = bodyToJson.user.id
       return f.return(userId)
  }
  else {
    f.throw(error)
  }
})
  return f.wait()
}


function nextFunction(data) {
 //do some thing with data
 } 

Meteor.methods({
 sequenceAsyncFunctions: function() {
  try {
     var resultOne = requesting()
     var resultTwo = nextFuntion(resultOne)
      } catch (e) {
      //handling my errors
      }
  }
})

Upvotes: 1

Views: 922

Answers (2)

user3374348
user3374348

Reputation: 4101

I noticed you tagged this question . Meteor uses Fibers on the server. This package gives you co-operative multitasking using a sort of lightweight thread (called a fiber). This allows you to write "blocking" functions like your requesting without actually blocking the event loop. Future lets you use callback-based node.js functions in a blocking way using Fibers.

Without Fibers, it is impossible to write a function like your requesting which does I/O and returns the result directly. Instead you'd have to pass a callback (or use promises).

Idiomatic Meteor code should make use of Fibers on the server to make "blocking" functions. This is how the core Meteor APIs work, and is necessary inside Meteor methods. Rather than using future, you might find Meteor.wrapAsync more convenient.

In regular node.js code you could use Fibers, but it's more common to use function (err, result) {...} callbacks or promises. In the browser (including Meteor client code) you can't use Fibers, so you have to use callbacks or promises.

Here's how you would sequence operations using future, regular callbacks and promises:

// Future
function doTwoThings() {
    var future = new Future();
    asyncFunction(argument, function (err, result) {
        if (err) future.throw(err);
        else future.return(result);
    });
    var result = future.wait();

    var future2 = new Future();
    anotherAsyncFunction(result, function (err, result2) {
        if (err) future2.throw(err);
        else future2.return(result2);
    });
    var result2 = future2.wait();
    return result2 + 2;
}

// wrapAsync
var wrappedAsyncFunction = Meteor.wrapAsync(asyncFunction);
var wrappedAnotherAsyncFunction = Meteor.wrapAsync(anotherAsyncFunction);
function doTwoThings() {
    var result = wrappedAsyncFunction(argument);
    var result2 = wrappedAnotherAsyncFunction(anotherAsyncFunction);
    return result2 + 2;
}

// Regular callbacks
function doTwoThings(callback) {
    asyncFunction(argument, function (err, result) {
        if (err) return callback(err);

        anotherAsyncFunction(result, function (err, result2) {
            if (err) return callback(err);
            callback(null, result2 + 2);
        });
    });
}

// Promises
function doTwoThings() {
    return asyncFunctionReturningPromise(argument).then(function (result) {
        return anotherAsyncFunctionReturningPromise(result);
    }).then(function (result2) {
        return result2 + 2;
    });
}

Upvotes: 1

AdrieanKhisbe
AdrieanKhisbe

Reputation: 4058

'callback' wait for objects to be passed into the arguments

in fact the callback does not wait for the object. The callback is called with the argument by the function you give it has argument.


You could use one of the promise library such as Q to handle this

Here is some article describing it in more depth

Some alternatives are Kew and Async.

Promises have been specified, you can see more details and library here: http://wiki.commonjs.org/wiki/Promises/A

Upvotes: 2

Related Questions