我是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)
}
})
答案 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)
}