2012-03-30 4 views
9

Ho un'applicazione nodo che è non un'applicazione Web - completa una serie di attività asincrone prima di tornare 1. Immediatamente prima di tornare, i risultati del programma vengono stampati sulla console.Come scrivere una funzione node.js che aspetta un evento prima di "tornare"?

Come si assicura che tutto il lavoro asincrono sia completato prima di tornare? Sono stato in grado di ottenere qualcosa di simile a questo in un'applicazione web assicurandomi che tutte le attività completate prima di chiamare res.end(), ma non ho alcun equivalente per un 'evento' finale da chiamare prima di lasciare il ritorno di uno script.

Vedere sotto per la mia funzione (interrotta) al momento, il tentativo di attendere che callStack sia vuoto. Ho appena scoperto che questo è un tipo di approccio non sensato perché il nodo attende il completamento di processHub prima di immettere una qualsiasi delle funzioni asincrone chiamate in processObjWithRef.

function processHub(hubFileContents){ 
    var callStack = []; 
    var myNewObj = {}; 
    processObjWithRef(samplePayload, myNewObj, callStack); 
    while(callStack.length>0){ 
     //do nothing 
    } 
    return 1 
} 

Nota: Ho provato molte volte in precedenza per ottenere questo tipo di comportamento con le librerie come asincrona (vedere la mia domanda relativa al How can I make this call to request in nodejs synchronous?) quindi si prega di prendere la risposta e commenti là in considerazione prima di proporre eventuali risposte sulla base di ' basta usare asynch '.

+1

"Come faccio a essere sicuro tutto il lavoro asincrona viene completata prima di tornare ?" È una domanda priva di senso: il controllo non viene mai restituito alla shell fino a quando non sono state completate tutte le attività asincrone, quindi lasciare l'output della console solo dopo che l'ultima funzione asincrona ha risolto il problema. Grazie a tutti per aver inviato le risposte. – Trindaz

risposta

5

Il problema riguarda il design della funzione. Si desidera restituire un risultato sincrono da un elenco di attività eseguite in modo asincrono.

È necessario implementare la funzione con un parametro aggiuntivo che costituirà la richiamata in cui si inserirà il risultato (in questo caso 1) per alcuni utenti che devono fare qualcosa con esso.

Inoltre è necessario avere un parametro di richiamata nella funzione interna, altrimenti non si saprà quando finisce. Se questa ultima cosa non è possibile, allora dovresti fare un qualche tipo di polling (usando setInterval forse) per verificare quando l'array callStack è popolato.

Ricorda che in Javascript non dovresti mai fare un'attesa impegnativa. Ciò bloccherà completamente il tuo programma mentre viene eseguito su un singolo processo.

1

Il problema è che node.js è a thread singolo, il che significa che se una funzione viene eseguita, nient'altro viene eseguito (ciclo di eventi) finché tale funzione non viene restituita. Quindi non è possibile bloccare una funzione per farla tornare dopo che è stata eseguita una procedura asincrona.

È possibile, ad esempio, impostare una variabile contatore che conta le attività asincrone avviate e decrementa tale contatore utilizzando una funzione di richiamata (che viene chiamata dopo che l'attività è stata completata) dal codice asincrono.

5

Non si può attendere un evento asincrono prima di tornare - questa è la definizione di asincrono! Cercare di forzare Node in questo stile di programmazione ti causerà solo dolore. Un esempio ingenuo sarebbe controllare periodicamente per vedere se callstack è vuoto.

var callstack = [...]; 

function processHub(contents) { 
    doSomethingAsync(..., callstack); 
} 

// check every second to see if callstack is empty 
var interval = setInterval(function() { 
    if (callstack.length == 0) { 
    clearInterval(interval); 
    doSomething() 
    } 
}, 1000); 

Invece, il solito modo di fare cose asincrona in nodo è quello di implementare una funzione di callback per la vostra funzione.

function processHub(hubFileContents, callback){ 
    var callStack = []; 
    var myNewObj = {}; 
    processObjWithRef(samplePayload, myNewObj, callStack, function() { 
    if (callStack.length == 0) { 
     callback(some_results); 
    } 
    }); 
} 

Se davvero si vuole restituire qualcosa, controlla promises; sono garantiti per emettere un evento immediatamente o ad un certo punto nel futuro quando vengono risolti.

function processHub(hubFileContents){ 
    var callStack = []; 
    var myNewObj = {}; 
    var promise = new Promise(); 

    // assuming processObjWithRef takes a callback 
    processObjWithRef(samplePayload, myNewObj, callStack, function() { 
    if (callStack.length == 0) { 
     promise.resolve(some_results); 
    } 
    }); 

    return promise; 
} 

processHubPromise = processHub(...); 
processHubPromise.then(function(result) { 
    // do something with 'result' when complete 
}); 
0

Avrai bisogno di iniziare a progettare e pensare in modo asincrono, che può richiedere un po 'di tempo per abituarsi in un primo momento. Questo è un semplice esempio di come affrontare qualcosa come "tornare" dopo una chiamata di funzione.

function doStuff(param, cb) { 
    //do something 
    var newData = param; 
    //"return" 
    cb(newData); 
} 

doStuff({some:data}, function(myNewData) { 
    //you're done with doStuff in here 
}); 

C'è anche un sacco di funzioni utili di utilità nella libreria async accessibile NPM.

3

deasync è progettato per risolvere esattamente il problema. Basta sostituire

while(callStack.length>0){ 
    //do nothing 
} 

con

require('deasync').loopWhile(function(){return callStack.length>0;}); 
1

Node.js viene eseguito su un ciclo di eventi filettato SINGLE e sfrutta le chiamate asincrone per fare varie cose, come le operazioni di I/O.

se è necessario attendere per un certo numero di operazioni asincrone per finire prima di eseguire codice aggiuntivo si può provare a utilizzare Async -

Node.js Async Tutorial