【发布时间】:2023-03-19 16:14:01
【问题描述】:
假设您想下载图像或文件,这将是互联网教您继续前进的第一种方式:
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 个管道请求将填满你的内存并导致节点崩溃。这就是为什么你需要回调而不是管道,所以你知道什么时候开始下一个文件。
【问题讨论】:
-
管道会更有效,因为它会在数据可用时将数据流式传输到
WriteStream。不过,我不认为你的最后一句话是真的。 -
好像是这样。尝试下载 50 个文档。您将得到 “检测到可能的 EventEmitter 内存泄漏。添加了 11 个侦听器。使用emitter.setMaxListeners() 增加限制。” 下载500,您的内存将填满并崩溃节点。这就是为什么你需要回调而不是管道,所以你知道什么时候开始下一个文件。
-
Resandro,我认为您混淆了流式传输、回调和流控制。流控制将正确维护传出连接的限制(请参阅 async.queue、async.eachLimit 等),但在回调/缓冲范例和流范例中,您需要流控制和资源管理。这些主题是不同的。