想象一下,如果您想下载图片或文件,这将是互联网教您继续前进的第一种方式:
request(url, function(err, res, body) {
fs.writeFile(filename, body);
});
但是这不会累积body
中的所有数据,填满内存吗?
pipe
会更有效率吗?
request(url).pipe(fs.createWriteStream(filename));
或者这是在内部处理类似的事情,无论如何缓冲流,使这无关紧要?
此外,如果我想使用回调但不 body
(因为你仍然可以pipe
),这个内存缓冲区是否仍会被填充?
我问,因为第一个(回调)方法允许我链接下载而不是并行启动它们(*),但我不想填充缓冲区我也不会使用。所以我需要回调,如果我不想诉诸async之类的东西只是为了使用queue来防止这种情况。
(*)这是不好的,因为如果你的文件在完成之前只有request
太多,request
的异步性质将导致节点在过量事件和内存丢失时窒息死亡。首先,你会得到这些:
"possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit."
当拉伸它时,500个管道请求将填满你的内存和崩溃节点。这就是为什么你需要回调而不是管道,所以你知道何时开始下一个文件。
答案 0 :(得分:3)
但这不会累积身体中的所有数据,填补内存吗?
是的,很多操作如你的第一个片段缓冲数据到内存中进行处理。是的,它使用内存,但它至少是方便的,有时需要,具体取决于您打算如何处理该数据。如果你想加载一个HTTP响应并将主体解析为JSON,那几乎总是通过缓冲来完成,虽然它可以通过流解析器实现,但它要复杂得多,而且通常是不必要的。大多数JSON数据都不够大,因此流媒体是一个巨大的胜利。
或者这是在内部以类似的方式处理,使这无关紧要?
不,以字符串形式提供整个数据的API使用缓冲而不是流式传输。
然而,多媒体数据,是的,你不能真实地将它缓冲到内存,因此流媒体更合适。此外,数据往往是不透明的(你不解析它或处理它),这也适用于流式传输。
当环境允许时,流媒体很好,但这并不意味着缓冲有任何必然的错误。事实是缓冲是绝大多数事情大部分时间都在起作用的方式。从大图来看,流式传输只是一次缓冲一个块,并将它们限制在可用资源范围内的某个大小限制。如果要处理数据,某些部分数据需要在某个时刻通过内存。
因为如果您只是逐个请求太多文件,请求的异步性质将导致节点在过量事件和内存丢失时窒息死亡。
不确定你在这里说什么/问什么,但是,编写有效的程序需要考虑资源和效率。
另见substack's rant on streaming/pooling in the hyperquest README。
答案 1 :(得分:1)
我找到了一个解决方案,使得关于记忆的问题无关紧要(尽管我仍然很好奇)。
如果我想使用回调但不
body
(因为你仍然可以pipe
),这个内存缓冲区是否仍会被填充?
您不需要callback
中的request()
来了解请求何时完成。当pipe()
'结束'时,stream
将自动关闭。关闭会发出一个事件,可以收听:
request(url).pipe(fs.createWriteStream(filename)).on('close', function(){
next();
});
现在,您可以将所有请求排队并逐个下载文件。
当然,您可以使用async.queue
之类的库一直使用8个并行请求来清理互联网,但如果您只想获得一些带有简单脚本的文件,async
可能是{{1}}矫枉过正。
此外,无论如何,您不希望在多用户系统上为单个技巧最大化系统资源。