Node js如何每2秒运行axios.get?

时间:2019-07-03 19:44:19

标签: javascript node.js asynchronous axios

我是node js的新手,这是我想要做的事情:我正在循环内通过map函数(大约3000个链接)遍历一个包含我们网站链接的json文件,为每个链接执行axios获取并获取响应状态代码(将来会做其他事情)。但是我只想每2秒钟或5秒钟就运行一次axios,否则我将使Web服务器不堪重负。我正在尝试输入异步等待,但它仍然太快,服务器受到打击(从技术上讲,我在DDos中使用我自己的网站)。我在axios周围放置了SetTimeout,但似乎不起作用,因为在控制台中,打印结果的速度太快了。 所以问题是,如何使每个axios.get请求每2秒等待一次,然后再在地图循环中运行?。

var axios = require('axios');
const fs = require('fs');
var statusCheck = 0;

var main = [];
let rawdata = fs.readFileSync('C:/Users/jay/Documents/crawl/filtered2.json');
let jsonParsed = JSON.parse(rawdata);

jsonParsed.map(async(line) => {

    var encodeLink = encodeURI(line.link);
    const response = await axios.get(encodeLink).catch((err) => {
        var Status_ErrorsCatchaxios = {
            "status Code": err.response.status ? err.response.status : "No status code available",
            "Page title:": $('title').text() ? $('title').text() : 'No title avaialble',
            "Original Link": encodeLink ? encodeLink : "No Original Link Available",
            "errorCode": err
        }
        main.push(Status_ErrorsCatchaxios)
    })
    try {
        console.log(response.status)

        statusCheck = statusCheck + 1;
        console.log("Link: ", statusCheck)
    } catch (error) {
        console.log(error)
    }
})

6 个答案:

答案 0 :(得分:1)

抛弃map,用for ... of替换,等待一个需要2秒钟才能解决的Promise,将所有内容包装在异步IIFE中,以使等待合法。

// dummy data
const fakeJson = new Array(5).fill();
const fakeRequest = () => console.log(`request at ${new Date().toUTCString()}`);

// iteration with 2s in between
(async () => {
  for (let line of fakeJson) {
    await new Promise(r => setTimeout(r, 2000));
    fakeRequest();
  }
})()

您也可以使用更传统的setInterval来使用,但是HTTP请求是异步的,因此也可以从处理异步和循环的结构开始。

答案 1 :(得分:1)

由于.map.forEach.reduce等不等待Promise解决,您一次都打了。使用Simple For循环,它将等待每个承诺解决或拒绝。

for(let i=0;i<jsonParsed.length;i++) {
    var encodeLink = encodeURI(line.link);
    const response = await axios.get(encodeLink).catch(...)
    try {
        ....
    } catch (error) {
        ...
    }
})

为什么不起作用? 如果我们模仿forEach循环,将类似于

function forEach(arr, cb){
    for(let i=0;i<arr.length;i++){
        cb(arr[i], i, cb);
    }
}

所以您看到它不是await的{​​{1}}。

答案 2 :(得分:1)

[].map函数不会等待项目解析,因此您的代码当前正在并行调度所有请求(如您所说,大约3000个)。

您可以使用for...of来一次仅运行一个请求。例如:

async function makeRequests (lines) {
  for (const line of lines) {
    const encodedLink = encodeURI(line.link)
    const response = await axios.get(encodedLink)
    // ...your response handling code here...
  }
}

makeRequests(jsonParsed)

如果您希望在每个请求之间等待2秒,则可以在for...of循环中添加以下代码行:

await new Promise(resolve => setTimeout(resolve, 2000))

更好的解决方案

以上解决方案有效,但我认为您的网络服务器一次可能可以处理多个请求,因此,理想的情况是将您的代码限制为最多只包含 N 个请求在给定时间平行。这样,您就不会淹没服务器,但是比一次只执行一个请求更快地获得结果。

通过bluebird NPM模块,您可以使用其Promise.map功能。

此函数将您的项目列表作为第一个参数,将执行某项并为每个项目返回promise的函数作为第二个参数,以及一个带有concurrency键的对象,该对象描述了您想要多少个项目允许作为第三个参数并行处理。

这是它的工作方式:

const bluebird = require('bluebird')

async function makeRequests (lines) {
  await bluebird.map(
    lines,
    async (line) => {
      const encodedLink = encodeURI(line.link)
      const response = await axios.get(encodedLink)
      // ...your response handling code here...
    },
    { concurrency: 3 }
  )
}

makeRequests(jsonParsed)

答案 3 :(得分:1)

超时无法循环运行的原因是,它会在timeout延迟后立即触发所有请求/功能。

这个想法是在每次迭代中放置延迟,并且只有在延迟开始下一个迭代之后。

您可以运行自调用功能,该功能在延迟后会自行调用。因此,要每2秒运行一次此功能,您可以尝试以下操作:

let jsonParsed = JSON.parse(rawdata);
let len = jsonParsed.length;

(function requestLoop (i) {          
    setTimeout(function () {   
        let line = jsonParsed[len-i]
        var encodeLink = encodeURI(line.link);
        const response = await axios.get(encodeLink).catch((err) => {
            var Status_ErrorsCatchaxios = {
                "status Code": err.response.status ? err.response.status : "No status code available",
                "Page title:": $('title').text() ? $('title').text() : 'No title avaialble',
                "Original Link": encodeLink ? encodeLink : "No Original Link Available",
                "errorCode": err
            }
            main.push(Status_ErrorsCatchaxios)
        })
        try {
            console.log(response.status)

            statusCheck = statusCheck + 1;
            console.log("Link: ", statusCheck)
        } catch (error) {
            console.log(error)
        }                        
        let jsonParsed = JSON.parse(rawdata);

        if (--i) requestLoop(i);     
   }, 2000)
})(len);

答案 4 :(得分:0)

您可以使用setTimeout函数每2秒运行一次代码!

setTimeout(async() => {
 // await postRequest()
},2000)

答案 5 :(得分:0)

你可以使用

var i=0;
jsonParsed.map(async(line) => {
i++
setTimeout(async() => {

},i*2000)
}