如何在循环中依次运行请求?

时间:2018-12-11 06:20:02

标签: javascript node.js mongodb express request

这是我要实现的伪代码。首先,我需要从请求主体中获取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,这就是为什么至少出于我的理解,它才需要处于循环中的原因。我希望请求按顺序运行,即它应该解析第一个网址,然后解析第二个,依此类推,当所有网址都完成后,它应该响应。请帮忙!

4 个答案:

答案 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();
            });
        }
    });