1

I want function cb to be called only after function f1 and f2 have been finished (note that f1 and f2 are asynchronous and they might be called out of order at any time).

I'm trying to implement something like this, but it doesn't seem the best way to do this on node.js.

var l1 = false;
var l2 = false;

// function to be called after f1 and f2 have ended
function cb(err, res) {
  if (err) {
    console.log(err);
  } else {
    console.log('result = ' + res);
  }
}

// f1 and f2 are practically identicals...
function f1(callback) {
  console.log('f1 called');
  l1 = true;
  if (l2) {
    console.log('f1 calling cb');
    callback(null, 'one');
  } else {
    console.log('f2 wasn\'t called yet');
  }
}

function f2(callback) {
  console.log('f2 called');
  l2 = true;
  if (l1) {
    console.log('f2 calling cb');
    callback(null, 'two');
  } else {
    console.log('f1 wasn\'t called yet');
  }
}

setTimeout(function() {
  f1(cb); // will call cb
}, 3000);
setTimeout(function() {
  f2(cb); // won't call cb
}, 1000);

// It will print:
// f2 called
// f1 wasn't called yet
// f1 called
// f1 calling cb
// result = one
orangesky
  • 305
  • 3
  • 8
  • 2
    Use promises to achieve this. – Akhoy May 17 '16 at 04:49
  • 1
    Are you willing to use an external library? There is a popular one for scenarios like this and many others, called [async](https://github.com/caolan/async). If you say you're willing I'll write an answer explaining how to apply it to this specific scenario. – Patrick Roberts May 17 '16 at 04:53
  • Yes, indeed I was looking for a solution using an external library. I looked into the async module but couldn't find anything helpful. – orangesky May 17 '16 at 04:58
  • 1
    Related: http://stackoverflow.com/questions/4631774/coordinating-parallel-execution-in-node-js/4631909#4631909 but generally these days I'd recommend async.js – slebetman May 17 '16 at 05:18

1 Answers1

3
var async = require('async');

console.log('before invocation');

async.parallel([
  function f1(cb) {
    console.log('f1 invoked');

    setTimeout(function () {
      console.log('f1 calling back');
      cb(null, 'one');
    }, 3000);
  },
  function f2(cb) {
    console.log('f2 invoked');

    setTimeout(function () {
      console.log('f2 calling back');
      cb(null, 'two');
    }, 1000);
  }
], function callback(err, results) {
  console.log('callback invoked');

  if (err) {
    console.log(err);
  } else {
    console.log('results: ', results);
  }
});

console.log('after invocation');

setTimeout(function () {
  console.log('2 seconds later...');
}, 2000);

Output:

before invocation
f1 invoked
f2 invoked
after invocation
f2 calling back
2 seconds later...
f1 calling back
callback invoked
results:  [ 'one', 'two' ]

Excuse the fact that I didn't replicate your scenario perfectly, but I'm acknowledging that what you had was a mock-up anyway.

The only difference is the final callback contains an array of the results from each of the functions executed in parallel, and the setTimeout() is called inside each of the functions.

Notice that the returned array is ['one', 'two'], because that's the order of the functions passed to async.parallel(). The cb argument provided to each of the functions is generated by async, which automatically does error-handling and other background processing for you, similar to how you had your two flags, but a little more organized and efficient.

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
  • The problem I see with this solution is that both f1 and f2 functions are called when async.parallel() is called. I actually don't have the information about when f1 or f2 will be called (they are independent). f1 could be called now and f2 2 minutes later for example. The setTimeout was just an example, I should have something like this instead: handler.on('some_event', f1); handler.on('other_event', f2); Thanks for helping though! – orangesky May 18 '16 at 00:48
  • @orangesky if you could elaborate on what invokes `f1` and `f2` and also what these two functions are supposed to do (other than handle flags for your final callback), I could give you a better answer. But without that information it's hard to tell exactly what I'm dealing with. – Patrick Roberts May 18 '16 at 00:56