这是我要实现的伪代码。首先,我需要从请求主体中获取URL列表,然后将这些URL传递给请求函数(使用请求模块),该函数将从每个URL获取数据,然后将这些数据保存到MongoDB。完成所有请求(包括仅将数据保存到服务器)后,它应该发送响应。
app.post('/', (req, resp) => {
const { urls } = req.body;
urls.forEach((url, i) => {
request(url, function (err, resp, body) {
if (err) {
console.log('Error: ', err)
} else {
// function to save data to MongoDB server
saveUrlData(body);
console.log(`Data saved for URL number - ${i+1}`)
}
})
});
// Should be called after all data saved from for loop
resp.send('All data saved')
})
我已经尝试过此代码,并且如果请求已完成,则resp.send()函数当然可以运行而无需关心。使用此代码,我将在控制台上得到如下结果:
Data saved for URL number - 3
Data saved for URL number - 1
Data saved for URL number - 5
Data saved for URL number - 2
Data saved for URL number - 4
我可以以嵌套形式编写它们,但是变量urls
可以具有任意数量的url,这就是为什么至少出于我的理解,它才需要处于循环中的原因。我希望请求按顺序运行,即它应该解析第一个网址,然后解析第二个,依此类推,当所有网址都完成后,它应该响应。请帮忙!
答案 0 :(得分:0)
您应该查看JavaScript Promises
否则,您可以像这样执行递归请求:
app.post('/', (req, resp) => {
const { urls } = req.body;
sendRequest(urls, 0);
})
function sendRequest(urlArr, i){
request(urlArr[i], function (err, resp, body) {
if (err) {
console.log('Error: ', err)
}
else {
saveUrlData(body);
console.log(`Data saved for URL number - ${i+1}`)
}
i++;
if(i == urlArr.length) resp.send('All data saved') //finish
else sendRequest(urlArr, i); //send another request
})
}
我所要做的就是创建一个单独的函数,我可以一遍又一遍地调用,将url数组和基本索引0作为参数传递。每个成功的回调都会增加索引变量,该索引变量将再次传递给同一函数。冲洗并重复直到我的索引达到url数组的长度为止,然后从此处停止递归循环。
答案 1 :(得分:0)
您要等到所有api响应都获得并存储在db中之后,因此您应该执行async-await并使所有响应均化。 您可以使用Request-Promise模块代替request。因此,您将在每个请求的api调用中获得承诺,而不是回调。 并使用promise.all来推动数组中的所有request(module)调用。 使用async-await,您的代码执行将一直等到所有api调用均获得响应并存储在db中。
const rp = require('request-promise');
app.post('/', async (req, res) => {
try{
const { urls } = req.body;
// completed all will have all the api resonse.
const completedAll = await sendRequest(urls);
// now we have all api response that needs to be saved
// completedAll is array
const saved = await saveAllData(completedAll);
// Should be called after all data saved from for loop
res.status(200).send('All data saved')
}
catch(err) {
res.status(500).send({msg: Internal_server_error})
}
})
function sendRequest(urlArr, i){
const apiCalls = [];
for(let i=0;i < urlArr.length; i++){
apiCalls.push(rp(urlArr[i]));
}
// promise.all will give all api response in order as we pushed api call
return Promise.all(apiCalls);
}
您可以参考以下链接: https://www.npmjs.com/package/request-promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
答案 2 :(得分:0)
查看意图(搜寻器),您可以使用Promise.all
,因为这两个URL不相互依赖。
app.post('/', (req, resp) => {
const { urls } = req.body;
const promises = urls.map((url, i) => {
return new Promise((resolve, rej)=>{
request(url, function (err, resp, body) {
if (err) {
rej(err);
} else {
resolve(body);
}
})
})
.then((body)=>{
//this should definitely be a promise as you are saving data to mongo
return saveUrlData(body);
})
});
// Should be called after all data saved from for loop
Promise.all(promises).then(()=>resp.send('All data saved'));
})
注意:还需要进行错误处理。
答案 3 :(得分:0)
有多种解决方法。
您可以使用async/await
承诺
您还可以使用async library
app.post('/', (req, res, next) => {
const { urls } = req.body;
async.each(urls, get_n_save, err => {
if (err) return next(err);
res.send('All data saved');
});
function get_n_save (url, callback) {
request(url, (err, resp, body) => {
if (err) {
return callback(err);
}
saveUrlData(body);
callback();
});
}
});