2015-12-15 5 views
14

Sto lavorando a un progetto che utilizza Node.js per un plug-in Haraka (un server smtp).Come posso effettuare una richiamata che richiede informazioni sulla funzione figlio

Questo è Node.JS e ho un piccolo problema con i callback. Non sono stato in grado di convertire questo particolare codice per utilizzare una richiamata.

Quindi, questo è il codice che ho:

exports.hook_data = function (next, connection) { 
    connection.transaction.add_body_filter('', function (content_type, encoding, body_buffer) { 
     var header = connection.transaction.header.get("header"); 
     if (header == null || header == undefined || header == '') return body_buffer; 

     var url = 'https://server.com/api?header=' + header ; 
     var request = require('request'); 
     request.get({ uri: url }, 
      function (err, resp, body) { 
       var resultFromServer = JSON.parse(body); 
       return ChangeBuffer(content_type, encoding, body_buffer, resultFromServer); 
      } 
     ); 
    }); 
    return next(); 
} 

Questo codice non funziona perché non aspetta il richiamo della richiesta di continuare. Devo completare la richiesta prima dello next();

E questi sono i requisiti:

  1. Alla fine del exports.hook_data è obbligatoria per tornare next(). Ma deve solo restituirlo dopo la richiesta.
  2. Devo restituire un Buffer in add_body_filter ma ho bisogno di creare il buffer con le informazioni ottenute da un server.
  3. Per ottenere la richiesta di ricezione, è necessario utilizzare un parametro (header) che ho solo all'interno di add_body_filter.

Quindi il problema è che non riesco a fare la richiesta prima add_body_filter e mettere il risultato all'interno di una richiamata perché il parametro che ho bisogno di fare la richiesta sono solo all'interno add_body_filter.

Qualche consiglio, per favore?

+1

Non è possibile utilizzare un asincrona funzione in Javascript, ma richiede che si comporti in modo sincrono. Questo è semplicemente NON possibile. Se si dispone di un'operazione asincrona, è necessario eseguire il codice per utilizzarlo in modo asincrono. Ciò significa restituire risultati in una promessa o tramite un callback, NON tramite il valore di ritorno dalla funzione perché la funzione restituirà PRIMA che l'operazione asincrona sia completata. Probabilmente trarrai vantaggio dalla lettura di questo [Come restituire la risposta dall'operazione asincrona] (http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call/14220323 # 14.220.323). – jfriend00

+0

Puoi passare un callback a 'ChangeBuffer'? –

+0

E dove usi 'body_buffer' (vedi la linea # 4) e il risultato di' ChangeBuffer (content_type, encoding, body_buffer, resultFromServer) '(vedi la riga # 11) che restituisci? Immagino da nessuna parte, giusto? –

risposta

4

A meno che non si desideri utilizzare le funzioni sincrone e di blocco, è impossibile soddisfare i requisiti numerati.

Vorrei esaminare le ragioni alla base di ciascun requisito e vedere se si raggiungono i propri obiettivi in ​​un modo diverso.

sul valore nominale, guardando solo il codice che hai lì, vorrei cercare un modo per modificare il contratto di exports.hook_data in modo che siete in grado di chiamare next() dall'interno del request.get callback.

1

Utilizzare Async.js o Promises.

implementazione asincrona:

exports.hook_data = function (next, connection) { 
    async.waterfall([ 
    function(done) { 
     connection.transaction.add_body_filter('', function(content_type, encoding, body_buffer) { 
     var header = connection.transaction.header.get("header"); 
     if (header == null || header == undefined || header == '') { 
      done(null, body_buffer); 
     } 
     done(null, header); 
     }); 
    }, 
    function(header, done) { 
     var url = 'https://server.com/api?header=' + header; 
     var request = require('request'); 
     request.get({ uri: url }, 
     function(err, resp, body) { 
      // do something if there's an error 
      var resultFromServer = JSON.parse(body); 
      done(null, ChangeBuffer(content_type, encoding, body_buffer, resultFromServer)); 
     } 
    ); 
    } 
    ], function(error, buffer) { 
    // do something if there's error 
    next(buffer); 
    }); 
} 

C'è molto qui e vi consiglio di leggere la documentazione su async.js#waterfall. Essenzialmente, interrompe ogni chiamata asincrona nel suo blocco funzione e attende che ritorni prima che continui sul blocco successivo.

Anche in questo caso, poiché questi sono tutti asincroni, il nodo invia queste attività al ciclo di eventi IO ed è gestito da lì (non bloccante). Quando questo thread è in attesa, probabilmente passerà alla richiesta successiva mentre questa richiesta è in attesa.

0

Guardando il manuale Haraka per Transaction object & Header object non vedo v'è alcuna dipendenza di intestazione sul add_body_filter. Anche il tuo codice non mostra alcuna dipendenza su add_body_filter. Quindi il tuo terzo requisito sembra non valido.

Considerando che, penso che seguire pseudocodice (come non riesco a testarlo) dovrebbe funzionare per voi.

exports.hook_data = function (next, connection) { 
    var header = connection.transaction.header.get("header"); 
    if (header == null || header == undefined || header == '') { 
     return next(); 

    var url = 'https://server.com/api?header=' + header ; 
    var request = require('request'); 
    request.get({ uri: url }, 
     function (err, resp, body) { 
      var resultFromServer = JSON.parse(body); 
      connection.transaction.add_body_filter('', function (content_type, encoding, body_buffer) { 
       return ChangeBuffer(content_type, encoding, body_buffer, resultFromServer); 
      }); 
      next(); 
     } 
    ); 
} 

Se manuale Haraka è riuscita a mettere in evidenza la dipendenza di intestazione sul add_body_filter e/o si hanno scoperto che, sulla base di esperienze pratiche, quindi l'approccio di Quy sembra essere la strada da percorrere.

Se vi state chiedendo when to use next() v/s return next()

+0

purtroppo non è possibile utilizzare connection.transaction.header.get ("header") all'esterno add_body_filter. Puoi usarlo in un altro evento ma nell'evento Data restituirà sempre valori vuoti :( –

0

Per la gestione di priorità di ogni parte del codice che uso Q, Si può usare in pochi passi:

  1. npm install q.

    var request = require('request'); 
    var Q = require('q'); 
    
    exports.hook_data = function() { 
        var url, header; 
        Q() 
        .then(function(){ 
        connection.transaction.add_body_filter('', function(content_type, encoding, body_buffer) { 
    
         header = connection.transaction.header.get("header"); 
    
         if (header == null || header == undefined || header == ''){return body_buffer;} 
         url = 'https://server.com/api?header=' + header ; 
    
        }) 
        .then(function(){ 
    
         request.get({ uri: url }, function (err, resp, body) { 
    
          var resultFromServer = JSON.parse(body); 
    
          return ChangeBuffer(content_type,encoding,body_buffer,resultFromServer); 
         }); 
    
        }) 
    
    } 
    

In async scenari, utilizzando q per callback è più meglio di altri modi credo.

+0

sei sicuro dallo script sopra il corretto uso di Q. Dubbio a riguardo! –

+0

Sì ne sono assolutamente sicuro, ma non il modo migliore. Forse il modo migliore è usare 'Q.all' per essere sicuri dei dati necessari e con' .spread' continuare i passaggi. –

0

JavaScript è di natura asincrona. Asincrono è una sequenza di programmazione che fornisce la funzione di codice non bloccante, ovvero non arrestare o non dipendere da un'altra funzione/processo per eseguire una riga di codice specifica . Rif: Codementor Article

Da Wikipedia

Node.js fornisce un'architettura event-driven e un non-blocking API I/O progettato per ottimizzare il throughput e la scalabilità di un'applicazione per le applicazioni web in tempo reale

Cosa puoi fare?

  1. Usare un sonno/attendere cioè setTimeout (Non raccomandato)
  2. Usa alcuni asincrona lib come https://github.com/caolan/async (consigliata)
  3. Usa qualche promessa lib come Q
Problemi correlati