2012-03-10 13 views
7

У меня есть код, какПоследовательное выполнение в node.js

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

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

ответ

13

Как вы, вероятно, знаете, все выполняется асинхронно в 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, чтобы увидеть все вспомогательные функции, которые он предоставляет, это очень полезно!

+0

вместо итерации по result.tasks мы можем итерации объекта результата (JSON)? я попытался, но он дает мне ошибку, например Object # не имеет метода 'foreach', а также видит все вспомогательные функции async, но нет функции для итерации объектов. –

+0

Вы можете перебирать массив, находящийся в JSON ... звучит так, как будто у вас есть объект, поэтому вы не можете перебирать его. Если вам нужна помощь в обработке объекта JSON, отправьте новый вопрос. – staackuser2

+3

Вопрос задает «Последовательное выполнение в node.js». Это делается как раз наоборот. Следовательно, мое пониженное голосование –

5

Я недавно создал простую абстракцию под названием «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); 
    }); 
Смежные вопросы