Confusione di callback e raccolta di dati nel nodo

Sono nuovo nel nodo e ho problemi a seguire quello che sta succedendo qui. il mio commento è sotto, ma fondamentalmente sto davvero lottando per capire perché il callback in utils.collectData è lì (secondo parametro) e come si aggiunge arbitrariamente alla matrice dei messaggi. come faccio a saperlo fare naturalmente in futuro? So che la funzione collectData è definita come prendere un callback come secondo argomento, quindi partiamo da lì …

var utils = require('./utils'); "POST": function(request, response) { //collect the data utils.collectData(request, function(message) { message.objectID = ++objectIDcounter; messages.push(message); utils.sendResponse(response, { objectID: message.objectID }, 201) }) } // this is in utils.js: //why is a callback parameter passed to this function? exports.collectData = function(request, callback) { var data = "" request.on('data', function(chunk) { data += chunk; }) request.on('end', function() { //why is the callback applied here? //Also, we are parsing the data here. why? because it is a buffer or a string here? callback(JSON.parse(data)); }) } 

Le operazioni asincrone in Node.js seguono uno schema semplice e coerente. Padroneggiare renderà la tua esperienza sostanzialmente più piacevole e le tue applicazioni più veloci e più stabili.

Penso che le altre risposte qui manchino un po ‘. Il metodo che stai chiamando segue un modello asincrono che è onnipresente nell’ecosistema Node.js. Esistono vari schemi per semplificare questo, ma il tuo primo compito dovrebbe essere quello di capire esattamente cosa sta succedendo e quale effetto ha sul tuo codice. È piuttosto semplice:

 asyncFunction(functionArguments, callback); 

Quando si chiama una funzione asincrona, lo script continua a essere eseguito mentre il risultato di quella funzione è in sospeso. Dato che non hai alcuna garanzia su quando i tuoi risultati saranno pronti, fornisci la funzione con le tue intenzioni per il risultato prima di proseguire. Spesso, il callback fornito dall’utente sarà una funzione anonima, ad esempio:

 getExternalData('http://example.com', function(err, data) { console.log('I got the data!'); // presumably do something with the data }); 

Il callback invariabilmente invariabilmente prende due argomenti: err e data (o err e result , o err e whateverYouAreLookingFor ). Se si verifica un errore nella funzione, verrà restituito al callback e, se i dati risultanti dall’esecuzione della funzione, verranno restituiti alla richiamata.

La bellezza di questo modello è che non sei mai costretto a bloccare il ciclo degli eventi: il tuo script rimane felicemente reattivo indipendentemente dalla complessità del suo compito. Quando il tuo capo lascia cadere un progetto mal concepito sulla tua scrivania subito dopo il pranzo di venerdì e poi lascia presto il lavoro per andare a giocare a golf, sei, in effetti, un gioco di ruolo come una funzione asincrona.

La sfida qui è che al momento in cui viene richiamato il callback, è l’unico collegamento superstite alla richiesta originale. Le implicazioni di questo sono duplici:

  1. Qualsiasi logica per l’elaborazione della risposta deve essere contenuta all’interno della richiamata o accessibile alla richiamata; e

  2. i blocchi try / catch sono completamente inutili per gestire gli errori generati dalla funzione asincrona.

La prima implicazione è la genesi di ciò che viene spesso descritto come “inferno di callback”: callback profondamente annidati all’interno di callback all’interno di callback. Puoi evitarlo abbastanza facilmente pianificando in anticipo, mantenendo le tue funzioni piccole e seguendo le stesse convenzioni per gli argomenti.

La seconda implicazione significa che il callback deve verificare la presenza di errori. Solitamente non vedrai errori lanciati, poiché l’unico modo per gestire in modo sicuro gli errori lanciati sotto questo schema sarebbe quello di posizionare quasi tutto il codice all’interno dei blocchi try / catch. Invece, gli errori verranno passati al callback come primo argomento. Se non è stato generato alcun errore, il primo argomento sarà nullo.

 const myCallback = function(err, data) { if (!!err) { console.log('Well, that was a failure'); return err; } console.log('Everything's great!'); } 

Questo ha finito per essere un po ‘prolisso, ma è di fondamentale importanza che tu ti senta a tuo agio con questo modello. Alcuni dei moduli principali hanno versioni normali e sincrone di funzioni, come fs.readFile e fs.readFileSync . Non soccombere a usarli; asincrono è piuttosto semplice una volta che vi siete abituati e, appena all’inizio, avete bisogno di tutta la pratica che potete ottenere.

Buona fortuna.

Una delle principali caratteristiche di NodeJs è la concomitanza (in modo semplice). Il modo migliore per iniziare a programmare in NodeJs è pensare che tutto il codice che interagisce con una risorsa esterna debba seguire uno dei seguenti pattern:

  • callback
  • Promessa (ES2015)
  • Async / Await (ES2016)

Perchè è questo?

Quando si chiama una risorsa esterna in modo asincrono (servizio HTTP, file, ecc.). Il processo principale crea un thread interno ed esegue il codice, ciò non impedisce il processo principale.

callback:

È stato il primo modo per gestire la concorrenza in javascript, poiché le funzioni sono di prima class, si passa solo la funzione che si desidera eseguire e la funzione principale sceglie quando chiamarla.

Nel tuo esempio, stai utilizzando questo approccio. Stai leggendo i dati dalla richiesta e memorizzato nella variabile locale, quando la richiesta avvia l’evento ‘fine’ che scegli chiami il callback con i dati come argomenti e il “POST” usa quei dati per manipolare il messaggio e inviare la risposta .

In futuro esistono altre due opzioni, entrambe potrebbero essere utilizzate oggi ma Async / Await è nella fase 2 di tc39 http://tc39.github.io/ecmascript-asyncawait/ .

Promettere:

È il modo più popolare oggi, è ansible utilizzare nativo con la versione 4 di NodeJs oppure è ansible utilizzare librerie come Q o BlueBird . Questo lavoro un po ‘diverso, consiglio di leggere il post sulla promise, qui ho intenzione di mostrare il tuo codice scritto usando le promesse:

 var utils = require('./utils'); "POST": function(request, response) { //collect the data utils.collectData(request) .then(function(message) { message.objectID = ++objectIDcounter; messages.push(message); return utils.sendResponse(response, { objectID: message.objectID }, 201); })) .catch(function(err) { //Some error happend with the reques }); } // this is in utils.js: //why is a callback parameter passed to this function? exports.collectData = function(request) { return new Promise(function (resolve, reject) { var data = "" request.on('data', function(chunk) { data += chunk; }); request.on('end', function() { resolve(JSON.parse(data)); }); request.on('error', function(err) { reject(err); }); } } 

Anche quando ho iniziato a programmare in NodeJS da Java, dato che è un importante cambiamento nella progettazione dei nostri programmi da Blocking IO a Non blocking IO, anch’io ho dovuto affrontare il codice precedente.

Qui in Non blocking IO tutto funziona in base a eventi e callback. Nel codice sopra richiamando collectData, nodejs (eventloop) attenderà on (con callback per raccogliere dati) e on (con callback che hai fornito per elaborare gli eventi completati).

Come semplice in NodeJS, qualsiasi codice di blocco (chiamata di rete o accesso a qualsiasi IO Device) verrà contrassegnato con un evento che verrà triggersto una volta completata l’operazione di I / O. Spero che questo ti aiuti.