我有一个循环,它遍历数组,在每次迭代中我都要做一个http请求,如下所示:
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
我无法在回调中执行for循环的其余部分,我必须等待从函数getData返回的结果并移动到下一次迭代。 如何处理?
PS我知道我可以使用回调函数但是如果在最后一次迭代程序之后会在最后一次getData执行完成之前发送响应(上一行)呢?
此致
答案 0 :(得分:2)
如约翰内斯的回答所述,使用承诺是一个好主意。由于您正在使用请求,我希望使用request-promise提出替代方法,bluebird是'请求'的预定版本。使用Promise.all()。
在这种情况下,请求将返回一个promise,并且通过使用.map()
,您可以使用创建一个可以等待的promise数组。当所有承诺都得到解决后,可以发送回复!这也与.reduce()
的使用不同,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
});
只在前一个请求完成后才开始执行下一个请求。通过使用promise数组,您可以同时启动所有请求。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.2</version>
</dependency>
答案 1 :(得分:1)
如果你需要在开始另一次迭代之前等待每次迭代,你可以使用Promises和reduce。如果您只想等待所有请求完成,最好使用map + Promise.all,如Daniel Bs的回答所述。
// 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
});
});
};