Javascript 如何在循环中按顺序运行请求?

Javascript 如何在循环中按顺序运行请求?,javascript,node.js,mongodb,express,request,Javascript,Node.js,Mongodb,Express,Request,这是我试图实现的一个伪代码。首先,我需要从请求主体获取url列表,然后将这些url传递给请求函数(使用请求模块),请求函数将从每个url获取数据,然后将这些数据保存到MongoDB。完成所有请求(包括仅将数据保存到服务器)后,服务器应发送响应 app.post('/', (req, resp) => { const { urls } = req.body; urls.forEach((url, i) => { request(url, funct

这是我试图实现的一个伪代码。首先,我需要从请求主体获取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
我可以用嵌套的形式编写它们,但是变量
url
可以有任意数量的url,这就是为什么至少从我的理解来看,它需要在循环中。我希望请求按顺序运行,即它应该解析第一个url,然后解析第二个url,依此类推,当所有url都完成时,它应该响应。请帮忙

你应该看看

否则,您可以执行如下递归请求:

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数组的长度,我将从此处停止递归循环

app.post('/', async (req, resp) => {

    const {
        urls
    } = req.body;

    for (const url of urls) {
        try {
            const result = await doRequest(url)
            console.log(result)

        } catch (error) {
            // do error processing here 
            console.log('Error: ', err)
        }
    }
})

function doRequest(url) {
    return new Promise((resolve, reject) => {
        request(url, function(err, resp, body) {
            err ? reject(err) ? resolve(body)
        })    
    })    
}
使用


您希望等待所有api响应并存储在db中,因此您应该执行异步等待并提示所有响应。 您可以使用请求承诺模块而不是请求。因此,您将在每个请求的api调用上获得承诺,而不是回调。 并使用promise.all在阵列内推高所有请求(模块)调用。 使用async wait,代码执行将等待所有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);
}
const rp=require('request-promise');
app.post('/',异步(req,res)=>{
试一试{
const{url}=req.body;
//全部完成后将具有所有api响应。
const completedAll=等待发送请求(URL);
//现在我们有了所有需要保存的api响应
//completedAll是数组
const saved=等待saveAllData(completedAll);
//应在从for循环保存所有数据后调用
res.status(200).send('所有数据已保存')
}
捕捉(错误){
res.status(500).send({msg:Internal_server_error})
}
})
函数sendRequest(urlArr,i){
常量apicall=[];
for(设i=0;i
您可以参考以下链接:

查看意图(一个爬虫),您可以使用
承诺。所有这些都是因为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'));
})

注意:还需要进行错误处理。

有多种方法可以解决此问题

  • 您可以使用
    async/await

  • 许诺

  • 您也可以使用


请求
不是基于承诺的模块,您不能直接等待它。您需要首先提示它,或者可以使用
axios
我希望请求按顺序运行,即它应该解析第一个url,然后解析第二个url,依此类推,当所有url都完成时,它应该响应
,但没有url依赖于其他url。所以也许你应该让它们平行。这会快得多。正是我要找的。但是如何使用async和Wait捕捉错误呢?例如,在
sendRequest
中,如果
rp()
在解析url时抛出错误,我将如何捕获该错误?如果有一个URL没有解析,它会停止解析其他URL吗?为了捕获错误,我使用了catch块。当我们使用async和Wait时,必须在try-catch块中使用它。如果sendRequest或saveAllData方法中的任何一个抛出错误或拒绝承诺,那么它将在catch块中处理。如果任何一个url没有解析,那么它将停止解析其他url,并直接拒绝该承诺。理想情况下,不应该出现错误,我们应该在api调用之前进行适当的数据验证,以便始终得到响应200。
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();
        });
    }
});