2014-04-28 22 views
40

Sono di fronte a piccoli problemi nel restituire un valore dalla funzione di callback in Node.js, cercherò di spiegare la mia situazione il più semplice possibile. Considerate Ho un frammento di codice, che prende URL e colpisce l'URL e fornisce l'output:Restituzione di un valore dalla funzione di callback in Node.js

urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {        
    var statusCode = response.statusCode; 
    finalData = getResponseJson(statusCode, data.toString()); 
}); 

ho cercato di avvolgere all'interno di una funzione e di restituire un valore come questo:

function doCall(urlToCall) { 
urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {        
    var statusCode = response.statusCode; 
    finalData = getResponseJson(statusCode, data.toString()); 
    return finalData; 
}); 
} 

Perché nella mia codice Node.js, ho un sacco di if-else dichiarazione in cui verrà deciso il valore di urlToCall, in questo modo:

if(//somecondition) { 
    urlToCall = //Url1; 
} else if(//someother condition) { 
    urlToCall = //Url2; 
} else { 
    urlToCall = //Url3; 
} 

Il fatto è che tutte le istruzioni all'interno a urllib.request rimarrà lo stesso, tranne il valore di urlToCall. Quindi sicuramente ho bisogno di mettere quei codici comuni all'interno di una funzione. Ho provato la stessa cosa ma in doCall mi restituirà sempre undefined. Ho cercato in questo modo:

response = doCall(urlToCall); 
console.log(response) //Prints undefined 

Ma se stampo valore all'interno doCall() esso stampe perfettamente, ma sarà sempre tornare undefined. Secondo la mia ricerca, sono venuto a sapere che non possiamo restituire valori dalle funzioni di callback! (è vero)? Se sì, qualcuno mi può consigliare come gestire questa situazione, in quanto voglio evitare il codice duplicato in ogni blocco if-else.

+0

"è vero?" - Sì, sicuramente. –

+0

@ JanDvorak, quindi non ho altre opzioni oltre alla duplicazione del codice? ;) –

+1

Il superamento di alcune delle proprie richiamate può aiutare? Credo di sì. –

risposta

77

Il numero undefined perché console.log(response) viene eseguito prima dello doCall(urlToCall);. È necessario passare anche una funzione di richiamata, che viene eseguita quando viene effettuata la richiesta .

In primo luogo, la vostra funzione. Passare un callback:

function doCall(urlToCall, callback) { 
    urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {        
     var statusCode = response.statusCode; 
     finalData = getResponseJson(statusCode, data.toString()); 
     return callback(finalData); 
    }); 
} 

Ora:

var urlToCall = "http://myUrlToCall"; 
doCall(urlToCall, function(response){ 
    // Here you have access to your variable 
    console.log(response); 
}) 

@Rodrigo, inviato un good resource nei commenti. Leggi le richiamate nel nodo e come funzionano. Ricorda, è un codice asincrono.

+0

+1 Grazie, il tuo esempio sembra buono. Cercherò di capire e implementarlo. –

+4

Funziona bene. Ma ho una domanda. nel chiamare la funzione doCall. Come posso restituire la variabile di risposta? Se ad esempio voglio ottenere quella variabile al di fuori della funzione? – Romeo

+0

@Romeo stessa domanda qui !! – himanshupareek66

10

Sto affrontando piccola difficoltà nel ritornare un valore da funzione di callback in Node.js

Questo non è un "piccolo problema", in realtà è impossibile "ritorno" di un valore nel tradizionale senso da una funzione asincrona.

Poiché non è possibile "restituire il valore", è necessario chiamare la funzione che avrà bisogno del valore una volta ottenuto. @display_name ha già risposto alla tua domanda, ma volevo solo far notare che il ritorno in doCall è senza restituire il valore nel modo tradizionale. Si potrebbe scrivere doCall come segue:

function doCall(urlToCall, callback) { 
    urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {        
     var statusCode = response.statusCode; 
     finalData = getResponseJson(statusCode, data.toString()); 
     // call the function that needs the value 
     callback(finalData); 
     // we are done 
     return; 
    }); 
} 

Linea callback(finalData); è quello che chiama la funzione che ha bisogno il valore che avete ottenuto dalla funzione asincrona.Ma essere consapevoli che l'istruzione return viene utilizzato per indicare che la funzione finisce qui, ma non significa che il valore viene restituito al chiamante (il chiamante già spostato su.)

2

Se quello che vuoi è far funzionare il tuo codice senza modificare troppo. Si può provare questa soluzione che si libera di callback e mantiene lo stesso flusso di lavoro Codice:

Dato che si sta utilizzando Node.js, è possibile utilizzare co e co-request per raggiungere lo stesso obiettivo senza preoccupazioni di callback.

In sostanza, si può fare qualcosa di simile:

function doCall(urlToCall) { 
    return co(function *(){ 
    var response = yield urllib.request(urlToCall, { wd: 'nodejs' }); // This is co-request.        
    var statusCode = response.statusCode; 
    finalData = getResponseJson(statusCode, data.toString()); 
    return finalData; 
    }); 
} 

Poi,

var response = yield doCall(urlToCall); // "yield" garuantees the callback finished. 
console.log(response) // The response will not be undefined anymore. 

In questo modo, ci aspettiamo che la funzione di callback finisce, quindi ottenere il valore da esso. In qualche modo, risolve il tuo problema.

+0

ma questo è ecma6 soultion –

+0

e ha un impatto anche sulle mie prestazioni –

+0

ecma6 è un problema? –

0

codice di esempio per node.js - Funzione asincrono per sincronizzare la funzione:

var deasync = require('deasync'); 

function syncFunc() 
{ 
    var ret = null; 
    asyncFunc(function(err, result){ 
     ret = {err : err, result : result} 
    }); 

    while((ret == null)) 
    { 
     deasync.runLoopOnce(); 
    } 

    return (ret.err || ret.result); 
} 
Problemi correlati