Javascript Node.js脚本是否静默失败?
我已经编写了一个Node.js脚本,它使用Javascript Node.js脚本是否静默失败?,javascript,node.js,asynchronous,callback,promise,Javascript,Node.js,Asynchronous,Callback,Promise,我已经编写了一个Node.js脚本,它使用download、axios和fs模块从提供的JSON中提取URL,并下载相关的PDF文件。但是,脚本通常无法下载所有PDF 无论出于什么原因,我的脚本在下载所有PDF文件之前都会“暂停”。也就是说,它一开始很好(下载了70、80个文件),但后来又停滞不前了。它不会触发我的捕捉块,也不会以任何方式失败。它只是停止下载 文件数量因我使用的wifi连接而异。但是,我始终无法完成代码,并在代码中触发。然后块。理想情况下,我希望使用.then块来处理下载后的文件
download
、axios
和fs
模块从提供的JSON中提取URL,并下载相关的PDF文件。但是,脚本通常无法下载所有PDF
无论出于什么原因,我的脚本在下载所有PDF文件之前都会“暂停”。也就是说,它一开始很好(下载了70、80个文件),但后来又停滞不前了。它不会触发我的捕捉块,也不会以任何方式失败。它只是停止下载
文件数量因我使用的wifi连接而异。但是,我始终无法完成代码,并在代码中触发。然后块。理想情况下,我希望使用.then块来处理下载后的文件
代码如下:
// The callback function that writes the file...
function writeFile(path, contents, cb){
mkdirp(getDirName(path), function(err){
if (err) return cb(err)
fs.writeFile(path, contents, cb)
})
};
// The function that gets the JSON...
axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
.then(downloadPDFS)
.catch((err) => {
console.log("COULD NOT DOWNLOAD FILES: \n", err);
});
// The function that downloads the data and triggers my write callback...
function downloadPDFS(res) {
const downloadPromises = res.data.results.map(item => (
download(item.pdf_url)
.then(data => new Promise((resolve, reject) => {
writeFile(`${__dirname}/${today}/${item.pdf_file_name}`, data, (err) => {
if(err) reject(err);
else resolve(console.log("FILE WRITTEN: ", item.pdf_file_name));
});
}))
))
return Promise.all(downloadPromises).then((res) => console.log("DONE"))
}
我的项目在Github上,如果您想安装它并自己尝试的话。下面用通俗易懂的英语总结一下正在发生的事情:
该脚本从服务器获取JSON,该服务器包含所有126个PDF的URL。然后,它将这些URL的数组传递给同步map
函数。每个URL都通过下载
模块转换为承诺。该承诺隐式返回,并存储在promise.all
包装器中。当下载承诺解决时(文档下载完成),我的自定义writeFile函数将触发,用下载的数据写入PDF文件。下载所有文件后,Promise.all
包装器应解析。但事实并非如此
出什么事了
编辑--
正如您在下面看到的,脚本运行了一段时间,但是它只是暂停,不再下载任何文件…
正如Jaromanda指出的,这可能与API限制我的访问有关,而不是与脚本中的错误有关
我在脚本中添加了一个过滤器,以选择更少的数据,它可以正常工作。详情如下:
axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
.then(downloadPDFS)
.then(() => {
console.log("DONE")
})
.catch((err) => {
console.log("COULD NOT DOWNLOAD FILES: \n", err);
});
function downloadPDFS(res) {
const EPA = res.data.results.filter((item) => {
return item.agencies[0].raw_name === "ENVIRONMENTAL PROTECTION AGENCY"; //// THIS FILTER
});
const downloadPromises = EPA.map(item => ( //// ONLY DOWNLOADING SOME OF THE DATA
download(item.pdf_url)
.then(data => new Promise((resolve, reject) => {
writeFile(`${__dirname}/${today}/${item.pdf_file_name}`, data, (err) => {
if(err) reject(err);
else resolve(console.log("FILE WRITTEN: ", item.pdf_file_name));
});
}))
))
return Promise.all(downloadPromises)
}
如果这确实是一个速率问题,那么有几种方法可以解决它(取决于API的速率限制)
下面是一个解决方案中的3个解决方案
费率限制
。。。这会触发每秒限制在给定数量的请求
singleQueue
。。。一次一个请求,没有速率限制,只是一系列的所有请求
多队列
。。。一次最多只能处理给定数量的“正在运行”请求
const rateLimited = perSecond => {
perSecond = isNaN(perSecond) || perSecond < 0.0001 ? 0.0001 : perSecond;
const milliSeconds = Math.floor(1000 / perSecond);
let promise = Promise.resolve(Date.now);
const add = fn => promise.then(lastRun => {
const wait = Math.max(0, milliSeconds + lastRun - Date.now);
promise = promise.thenWait(wait).then(() => Date.now);
return promise.then(fn);
});
return add;
};
const singleQueue = () => {
let q = Promise.resolve();
return fn => q = q.then(fn);
};
const multiQueue = length => {
length = isNaN(length) || length < 1 ? 1 : length;
const q = Array.from({ length }, () => Promise.resolve());
let index = 0;
const add = fn => {
index = (index + 1) % length;
return q[index] = q[index].then(fn);
};
return add;
};
// uncomment one, and only one, of the three "fixup" lines below
let fixup = rateLimited(10); // 10 per second for example
//let fixup = singleQueue; // one at a time
//let fixup = multiQueue(6); // at most 6 at a time for example
const writeFile = (path, contents) => new Promise((resolve, reject) => {
mkdirp(getDirName(path), err => {
if (err) return reject(err);
fs.writeFile(path, contents, err => {
if (err) return reject(err);
resolve();
})
})
});
axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
.then(downloadPDFS)
.catch((err) => {
console.log("COULD NOT DOWNLOAD FILES: \n", err);
});
function downloadPDFS(res) {
const downloadPromises = res.data.results.map(item => fixup(() =>
download(item.pdf_url)
.then(data => writeFile(`${__dirname}/${today}/${item.pdf_file_name}`, data))
.then(() => console.log("FILE WRITTEN: ", item.pdf_file_name))
));
return Promise.all(downloadPromises).then(() => console.log("DONE"));
}
const rateLimited=perSecond=>{
perSecond=isNaN(perSecond)| perSecond<0.0001?0.0001:perSecond;
常数毫秒=数学地板(1000/秒);
让承诺=承诺.解决(日期.现在);
const add=fn=>promise.then(lastRun=>{
const wait=Math.max(0,毫秒+lastRun-Date.now);
promise=promise.thenWait(等待)。然后(()=>Date.now);
回报承诺。然后(fn);
});
返回添加;
};
常量singleQueue=()=>{
让q=Promise.resolve();
返回fn=>q=q.then(fn);
};
常量多队列=长度=>{
长度=isNaN(长度)|长度<1?1:长度;
const q=Array.from({length},()=>Promise.resolve());
设指数=0;
const add=fn=>{
索引=(索引+1)%length;
返回q[index]=q[index],然后(fn);
};
返回添加;
};
//取消注释下面三行“fixup”中的一行,并且仅取消注释一行
let fixup=费率限制(10);//例如每秒10次
//设fixup=singleQueue;//一次一个
//设fixup=multiQueue(6);//例如,一次最多6个
const writeFile=(路径、内容)=>新承诺((解析、拒绝)=>{
mkdirp(getDirName(path),err=>{
如果(错误)返回拒绝(错误);
fs.writeFile(路径、内容、错误=>{
如果(错误)返回拒绝(错误);
解决();
})
})
});
axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
。然后(下载PDF)
.catch((错误)=>{
log(“无法下载文件:\n”,错误);
});
函数下载PDF(res){
const downloadPromises=res.data.results.map(项=>fixup(()=>
下载(item.pdf\u网址)
.then(data=>writeFile(`${uu dirname}/${today}/${item.pdf\u file\u name}`,data))
.then(()=>console.log(“文件写入:”,item.pdf\u文件名))
));
返回Promise.all(downloadPromises)。然后(()=>console.log(“完成”);
}
我还对代码进行了一点重构,因此下载PDF
仅使用承诺-所有节点回调样式的代码都放在写文件中
您对这个问题的原始标题是节点.js速率限制问题
-您认为您遇到一些未公开API的速率有问题吗?是的,就这么想出来了!谢谢你给我指明了正确的方向。我对API不太熟悉,我想这就是你被限制的原因吧?好像没办法知道我已经达到极限了,除非流量被切断?响应http状态将在4XX范围内,而不是2XX范围内-它真正深入到您的下载
函数是如何编写的-阅读github以获得下载
-不清楚它在何处/如何处理各种响应状态-可能是由它包含的另一个库完成的... 所以,是的,很难说到底发生了什么除了“限制”未公开API的类型之外,您有三种选择。。。1.最多并行发出n
请求(虽然n
是个谜),2。依次提出每个请求,3。限制为每秒n
请求。。。。。。但是,如果不知道极限是什么,就很难绕过它。。。我有三个场景的代码。。。(1.最多n
并行请求,2.串联请求尽可能快,3.串联请求限制在特定速率)-但不知道施加的限制我不知道