我想使用node.js开发高性能的文件下载器。我可能必须下载最大10GB的文件。我试过在内置的节点模块中使用。下面是代码:
var fs = require('fs');
var http = require('http');
var file = fs.createWriteStream('download.bin');
var contentLength;
var length;
var responseData = '';
var timeDiff = 0;
var fileurl = 'http://speed.hetzner.de/1GB.bin';
var request = http.get(fileurl, function (response) {
timeDiff = new Date().getTime();
contentLength = parseInt(response.headers['content-length']); // in bytes
length = [];
// Grab the data buffer of the request
response.on('data', (d) => {
responseData += d;
length.push(d.length);
let sum = length.reduce((a, b) => a + b, 0);
let completedParcentage = (sum / contentLength) * 100;
console.log(`completed reading ${sum} bytes out of ${contentLength} bytes`);
console.log(`${completedParcentage} percentage of download complete`);
if (completedParcentage == 100) {
console.log(new Date().getTime() - timeDiff, 'check-this-now');
}
});
response.on('end', () => {
file.write(responseData);
console.log(new Date().getTime() - timeDiff, 'check-this-now');
});
});
我正在从API下载1 GB的文件。我需要115秒才能完成。但我得到错误:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - **JavaScript heap out of memory**
1: node::Abort() [node]
2: 0x557f33ccc011 [node]
3: v8::Utils::ReportOOMFailure(char const*, bool) [node]
4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [node]
5: v8::internal::Factory::NewRawOneByteString(int, v8::internal::PretenureFlag)
阅读完文档后,我知道我们需要指定一些标志来增加堆大小。
但是有没有一种有效的方法可以在不使用内置模块的任何标志的情况下实现这一目标?
如果没有办法,您能建议使用NGINX服务的任何模块或体系结构吗?
注意:我也使用了请求,请求进行模块,它很好用,但我也想知道其他解决方案。
您的问题是这个:
responseData += d;
您正在将文件保存到RAM。无论您配置节点堆的大小如何,这都意味着您至少需要10GB的RAM来缓冲文件(我承认我不知道您的硬件,并且您可能有一台具有12GB或16GB RAM的计算机。我最大容量为8GB)。但是最糟糕的是,如果您的需求发生了变化,并且您需要下载20GB的文件,则需要升级硬件以具有20GB的RAM(或配置虚拟内存)。最重要的是,我什至不确定是否可以为节点配置10GB的堆。
而不是使用硬盘来缓冲下载的数据:
response.on('data', (d) => {
file.write(d); // THIS FIXES EVERYTHING
let sum += d.length;
let completedParcentage = (sum / contentLength) * 100;
console.log(`completed reading ${sum} bytes out of ${contentLength} bytes`);
console.log(`${completedParcentage} percentage of download complete`);
if (completedParcentage == 100) {
console.log(new Date().getTime() - timeDiff, 'check-this-now');
}
});
如果您不想意外地部分下载文件(如果下载不完整,那么您可以执行浏览器的操作并将其存储到临时文件中,然后在完成下载后重命名文件之前先将其存储到临时文件中:
var file = fs.createWriteStream('download.temp');
// then later
response.on('end', () => {
file.end(()=>{
// finish closing file
fs.rename('download.temp', 'download.bin', () => {
// finish renaming file
console.log(new Date().getTime() - timeDiff, 'check-this-now');
});
});
});