Последовательное выполнение в node.js - PullRequest
8 голосов
/ 10 марта 2012

У меня есть код как

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); 
  }
});

Он не выполняется последовательно в файле node.js, поэтому в конце выполнения я получаю пустой массив. Проблема в том, что он сначала выполнит console.log(tArr);, а затем выполнит

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

Есть ли какая-либо ошибка в моем коде или любой другой способ сделать это. Спасибо!

Ответы [ 2 ]

14 голосов
/ 10 марта 2012

Как вы, наверное, знаете, в node.js. все работает асинхронноПоэтому, когда вам нужно, чтобы все работало в определенном порядке, вам нужно использовать управляющую библиотеку или реализовать ее самостоятельно.

Я настоятельно рекомендую вам взглянуть на async ,поскольку это легко позволит вам сделать что-то вроде этого:

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);
  }
}

Главное, что нужно увидеть здесь, это то, что processEachTask вызывается с каждой задачей параллельно, поэтому порядок не гарантируется.Чтобы отметить, что задача была обработана, вы будете вызывать callback в анонимной функции с findOne.Это позволяет вам выполнять больше асинхронной работы в processEachTask, но все же удается определить, когда это будет сделано.Когда каждая задача будет выполнена, она вызовет afterAllTasks.

Взгляните на async , чтобы увидеть все вспомогательные функции, которые она предоставляет, это очень полезно!

6 голосов
/ 17 августа 2013

Недавно я создал простую абстракцию с именем " wait.for " для вызова асинхронных функций в режиме синхронизации (на основе волокон): https://github.com/luciotato/waitfor

Использование wait.for иасинхронно ваш код будет:

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);
    });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...