2017-01-17 3 views
0

Ich habe eine Schleife, die iteriert über Array und in jeder Iteration Ich habe eine HTTP-Anfrage zu tun, wie folgt aus:Funktion mit Asynchron-Anfrage in Knoten js

var httpsRequest = require('request') 
var getData = function(id) { 
     var result; 
    httpsRequest({ 
      url: 'https://link/'+id, 
     }, (error, resp, body) => { 
      if(resp.statusCode == 200) { 
       result = JSON.parse(body); 

      } 
     }); 
     //here I would like to wait for a result 
} 

var data = []; 
for(row in rows) { 
    data.push(getData(row.ID)) 
} 
resp.send(JSON.stringify(data)) //I send data back to the client 

ich den Rest der for-Schleife nicht tun können, Beim Callback muss ich auf ein Ergebnis warten, das von einer Funktion getData zurückgegeben wird und zur nächsten Iteration übergeht. Wie geht das?

PS Ich weiß, ich könnte Callback-Funktion verwenden, aber was ist, wenn nach dem letzten Iterationsprogramm die Antwort (letzte Zeile oben) vor der letzten Ausführung von getData senden wird?

Grüße

Antwort

2

Wie in der Antwort von Johannes erwähnt, ist die Verwendung von Versprechen eine gute Idee. Da Sie Anfrage verwenden, möchte ich eine alternative Methode vorschlagen, indem Sie request-promise verwenden, die eine promisifizierte Version von 'Anfrage' mit bluebird ist.

Die Anfragen werden in diesem Fall eine Zusage zurückgeben, und mit .map() können Sie eine Reihe von Versprechen erstellen, die Sie erwarten können, mit Promise.all(). Wenn alle Versprechen gelöst sind, kann die Antwort gesendet werden! Dies unterscheidet sich auch von der Verwendung von .reduce(), die nur dann mit der Ausführung der nächsten Anfrage beginnen wird, sobald die vorhergehende erledigt ist. Mit einem Array von Versprechen können Sie alle Anfragen gleichzeitig starten.

var httpsRequest = require('request-promise') 
var getData = function(id) { 
    return httpsRequest({ 
     url: 'https://link/' + id, 
    }, (error, resp, body) => { 
     if(resp.statusCode == 200) { 
      return JSON.parse(body); 
     } else { 
      //Throw error, this will be caught in the .catch() 
      throw error; 
     } 
    }); 
} 

var promises = rows.map(function(row){ 
    return getData(row.ID) 
}); 

Promise.all(promises) 
    .then(function(results){ 
     //All requests are done! 
     //The variable results will be an array of all the results in the same order as they were requested 
     resp.send(JSON.stringify(results)); 
    }) 
    .catch(function(error){ 
     //Handle the error thrown in the 'getData' function 
    }); 
1

Wenn Sie für jede Iteration warten müssen, bevor Sie ein anderes zu tun, Sie Promises und reduzieren können. Wenn Sie nur auf alle Anfragen warten möchten, ist es besser, map + Promise.all zu verwenden, wie in Daniel Bs Antwort erklärt.

// i asume rows is an array as you wrote you iterate over one. 
const results = []; 
rows.reduce((previous, row) => { 
    return previous.then(() => getData(row.ID).then(result => results.push(result)) // do whatever you want with the result 
); 
}, Promise.resolve()) 
.then(() => resp.send(JSON.stringify(results))); 

const getData = (id) => { 
    return new Promise((resolve, reject)=> { 
    httpsRequest({ 
     url: 'https://link/'+id, 
    }, (error, resp, body) => { 
     if(error) return reject(error); 
     if(resp.statusCode == 200) { 
     return resolve(JSON.parse(body)); 
     } 
     return resolve(); // if you want to pass non 200 through. You may want to do sth different here 
    }); 
    }); 
}; 
+0

Wofür steht "reduce"? –

+0

Obwohl dies funktioniert, besteht ein Nachteil von 'reduce()' darin, dass sie in der Reihenfolge ausgeführt werden, die nicht notwendig ist. –

+0

@DanielB Ich weiß, aber er sagte ausdrücklich, dass er warten möchte: > Ich muss auf ein Ergebnis warten, die von einer Funktion getData zurückgegeben werden und in die nächste Iteration –