2012-03-10 15 views
7

mam kod jaksekwencyjne wykonanie w 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); 
    } 
}); 

To nie jest wykonywane kolejno w node.js więc dostaję pustą tablicę na koniec realizacji. Problemem jest to pierwszy wykonać console.log(tArr); a następnie wykonać

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

Czy jest jakiś błąd w kodzie lub w inny sposób to zrobić. Dzięki!

Odpowiedz

13

Jak zapewne wiesz, rzeczy działają asynchronicznie w node.js. Kiedy więc chcesz uruchomić rzeczy w określonej kolejności, musisz skorzystać z biblioteki kontrolnej lub w zasadzie sam ją wdrożyć.

Gorąco proponuję spojrzeć na async, jak to łatwo pozwala zrobić coś takiego:

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

Główne rzeczy do zobaczenia tutaj jest to, że processEachTask jest wywoływana z każdego zadania równolegle , więc zamówienie nie jest gwarantowane. Aby oznaczyć, że zadanie zostało przetworzone, zadzwonisz pod numer callback w anonimowej funkcji z findOne. Dzięki temu możesz wykonać więcej pracy asynchronicznej w processEachTask, ale nadal udaje Ci się wskazać, kiedy to się stanie. Kiedy każde zadanie zostanie wykonane, zadzwoni ono pod numer afterAllTasks.

Spójrz na async, aby zobaczyć wszystkie funkcje pomocnika, które zapewnia, jest bardzo przydatny!

+0

zamiast iteracji wyników result.tasks możemy powtórzyć obiekt wynikowy (JSON)? próbowałem, ale daje mi błąd jak Object # nie ma metody "foreach", a także widzę wszystkie funkcje pomocnicze asynchroniczne, ale nie ma funkcji dla iteracji obiektu. –

+0

Możesz iterować po tablicy, która jest w JSON ... brzmi tak, jakbyś miał obiekt, więc nie możesz go powtórzyć. Jeśli potrzebujesz pomocy w obsłudze obiektu JSON, opublikuj nowe pytanie. – staackuser2

+3

Pytanie dotyczy "sekwencyjnego wykonywania w pliku node.js". To robi dokładnie odwrotnie. Stąd mój głos w dół –

5

I niedawno stworzyła prostą abstrakcję o nazwie „wait.for”, aby wywołać funkcje async w trybie synchronizacji (na bazie włókien): https://github.com/luciotato/waitfor

Korzystanie wait.for i asynchroniczny kod będzie:

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