8

I have code like

common.findOne('list', {'listId': parseInt(request.params. istId)}, function(err, result){       
  if(err) {
    console.log(err);
  }
  else {
    var tArr = new Array();               
    if(result.tasks) {
      var tasks = result.tasks;
      for(var i in tasks) {
        console.log(tasks[i]);
        common.findOne('tasks', {'taskId':parseInt(tasks[i])}, function(err,res){
          tArr[i]  = res;       
          console.log(res);                     
        });                       
      }
      console.log(tArr);
    }               
    return response.send(result); 
  }
});

It is not executed sequentially in node.js so I get an empty array at the end of execution. Problem is it will first execute console.log(tArr); and then execute

common.findOne('tasks',{'taskId':parseInt(tasks[i])},function(err,res){
      tArr[i]  = res;       
      console.log(res);                                         
});                       

Is there any mistake in my code or any other way for doing this. Thanks!

cdbitesky
  • 1,390
  • 1
  • 13
  • 30
priyanka patel
  • 617
  • 2
  • 10
  • 30

2 Answers2

16

As you are probably aware, things run asynchronously in node.js. So when you need to get things to run in a certain order you need to make use of a control library or basically implement it yourself.

I highly suggest you take a look at async, as it will easily allow you to do something like this:

var async = require('async');

// ..

if(result.tasks) {
  async.forEach(result.tasks, processEachTask, afterAllTasks);

  function processEachTask(task, callback) {
    console.log(task);
    common.findOne('tasks', {'taskId':parseInt(task)}, function(err,res) {
      tArr.push(res); // NOTE: Assuming order does not matter here
      console.log(res);
      callback(err);
    });
  }

  function afterAllTasks(err) {
    console.log(tArr);
  }
}

The main things to see here is that processEachTask gets called with each task, in parallel, so the order is not guaranteed. To mark that the task has been processed, you will call callback in the anonymous function from findOne. This allows you to do more async work in processEachTask but still manage to signify when it is done. When every task is done, it will then call afterAllTasks.

Take a look at async to see all the helper functions that it provides, it is very useful!

staackuser2
  • 12,172
  • 4
  • 42
  • 40
  • instead of iterate over result.tasks can we iterate a result object(JSON)? i tried but it gives me an error like Object # has no method 'foreach' and also see all helper functions of async but there is no function for object iteration. – priyanka patel Mar 12 '12 at 09:29
  • You can iterate over an Array that is in JSON... sounds like you had an Object though, so you can't iterate over that. If you need help with the handling the JSON object, post a new question. – staackuser2 Mar 12 '12 at 14:07
  • 3
    The question asks for "Sequential execution in node.js". This does exactly the opposite. Hence my down vote – Tom G Oct 01 '14 at 10:56
6

I've recently created a simple abstraction named "wait.for" to call async functions in sync mode (based on Fibers): https://github.com/luciotato/waitfor

Using wait.for and async your code will be:

var wait = require('waitfor');

...

//execute in a fiber
function handleRequest(request,response){
  try{
    ...
    var result = wait.for(common.findOne,'list',{'listId': parseInt(request.params.istId)});
    var tArr = new Array();               
    if(result.tasks) {
          var tasks = result.tasks;
          for(var i in tasks){
                console.log(tasks[i]);
                var res=wait.for(common.findOne,'tasks',{'taskId':parseInt(tasks[i])});
                tArr[i]  = res;       
                console.log(res);                     
          }
          console.log(tArr);
          return response.send(result); 
    };
    ....
  }
  catch(err){
      // handle errors
      return response.end(err.message); 
  }
};


// express framework
app.get('/posts', function(req, res) { 
    // handle request in a Fiber, keep node spinning
    wait.launchFiber(handleRequest,req,res);
    });
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Lucio M. Tato
  • 5,639
  • 2
  • 31
  • 30