How to write a node.js function that waits for an event to fire before 'returning'?

You cannot wait for an asynchronous event before returning--that's the definition of asynchronous! Trying to force Node into this programming style will only cause you pain. A naive example would be to check periodically to see if callstack is empty.

var callstack = [...];

function processHub(contents) {
  doSomethingAsync(..., callstack);
}

// check every second to see if callstack is empty
var interval = setInterval(function() {
  if (callstack.length == 0) {
    clearInterval(interval);
    doSomething()
  }
}, 1000);

Instead, the usual way to do async stuff in Node is to implement a callback to your function.

function processHub(hubFileContents, callback){
  var callStack = [];
  var myNewObj = {};
  processObjWithRef(samplePayload, myNewObj, callStack, function() {
    if (callStack.length == 0) {
      callback(some_results);
    }
  });
}

If you really want to return something, check out promises; they are guaranteed to emit an event either immediately or at some point in the future when they are resolved.

function processHub(hubFileContents){
  var callStack = [];
  var myNewObj = {};
  var promise = new Promise();

  // assuming processObjWithRef takes a callback
  processObjWithRef(samplePayload, myNewObj, callStack, function() {
    if (callStack.length == 0) {
      promise.resolve(some_results);
    }
  });

  return promise;
}

processHubPromise = processHub(...);
processHubPromise.then(function(result) {
  // do something with 'result' when complete
});

The problem is with your design of the function. You want to return a synchronous result from a list of tasks that are executed asynchronously.

You should implement your function with an extra parameter that will be the callback where you would put the result (in this case, 1) for some consumer to do something with it.

Also you need to have a callback parameter in your inner function, otherwise you won't know when it ends. If this last thing is not possible, then you should do some kind of polling (using setInterval perhaps) to test when the callStack array is populated.

Remember, in Javascript you should never ever do a busy wait. That will lock your program entirely as it runs on a single process.


deasync is desinged to address your problem exactly. Just replace

while(callStack.length>0){
    //do nothing
}

with

require('deasync').loopWhile(function(){return callStack.length>0;});