请求的回调是node.js中的错误做法吗?

时间:2013-11-08 00:25:06

标签: node.js request pipe

想象一下,如果您想下载图片或文件,这将是互联网教您继续前进的第一种方式:

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个管道请求将填满你的内存和崩溃节点。这就是为什么你需要回调而不是管道,所以你知道何时开始下一个文件。

2 个答案:

答案 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}}矫枉过正。

此外,无论如何,您不希望在多用户系统上为单个技巧最大化系统资源。