fandingo
fandingo

Reputation: 1360

NodeJS: Functions proceeding before previous function returns

I'm getting started with NodeJS with a script (not a webapp), and this is baffling to me. I have the following simplified functions:

var request = require('request');

function first_func(name) {
  console.log('first_func(' + name + ')');
  var url = 'http://...' + name;
  var answers = new Array();  
  request(url, function(error, resp, html) {
    ...
    answers.push(x);
  });
  return answers;
}

function second_func(answers) {
  var results = new Array();
  for (var a in answers) {
    var url = 'http://...' + a;
    request(url, function(error, resp, html) {
      ...
      results.push(x);
    });
  }
  return results;
}

first_func() scraps a directory page, and second_func() scraps the particular page for that entry. The script runs like this at the end of the script:

var names = ['a', 'b', ...];

function main() {
  for (var n in names) {
    var ans = first_func(names[n]);
    console.log('answers: ' + ans);
    for (var a in ans) {
      second_func(ans[a]);
    }
  }
}

main();

For some reason NodeJS is doing first_func() and second_func() in parallel. Why isn't it waiting for first_func() to complete before running second_func()? The output is:

answers: undefined

first_func(a)

first_func(b)

...

Why is NodeJS jumping into that inner for loop in main() before waiting for first_func() to return?

Upvotes: 0

Views: 66

Answers (1)

Timothy Strimple
Timothy Strimple

Reputation: 23060

You can use the async module to work around this. It would look something like the following:

var request = require('request');
var async = require('async');

function first_func(name, done) {
  console.log('first_func(' + name + ')');
  var url = 'http://...' + name;
  request(url, function(error, resp, html) {
    ...
    done(answers);
  });
}

function second_func(answers, done) {
  var results = new Array();
  async.each(answers, function(answer, next) {
    var url = 'http://...' + a;
    request(url, function(error, resp, html) {
      ...
      results.push(x);
      next();
    });
  }, function(err) {
    done(results);
  });
}

var names = ['a', 'b', ...];

function main() {
  async.each(names, function(name, next) {
    first_func(name, function(err, answers) {
      second_func(answers, function(results) {
        // do something wit results
        next();
      });
    });
  }, function(err) {
    // done will everything
  });  
}

main();

You basically call a function when you're done getting the values you need instead of returning them. The async module will let you iterate over arrays in an async friendly way.

Upvotes: 1

Related Questions