NodeJS http和非常大的响应主体

目前,我正在尝试从一个API(特别是这个 )请求一个非常大的JSON对象,这取决于各种因素,可以高达几MB。 但问题是,NodeJS需要永远做任何事情,然后只是内存不足:我的响应callback的第一行永远不会执行。

我可以单独要求每个项目,但这是一个巨大的要求。 引用新API背后的开发者:

到目前为止,如果你想获得宁静的所有市场订单,你必须要求每个地区的每个types。 这通常是50多个地区乘以13,000以上的types。 即使只有13000个types和50个地区,也就是650000个获取所有市场信息的请求。 如果您想在5分钟的caching窗口中获取所有数据,则每秒钟需要将近2200个请求。

显然,这不是一个好主意。

我正在尝试将数组items放入redis以供稍后使用,然后按照next url并重复,直到到达最后一页。 有没有办法做到这一点?

编辑:这是问题代码。 访问该url在浏览器中正常工作。

  // ... REGIONS.forEach((region) => { LOG.info(' * Grabbing data for `' + region.name + '#' + region.id + '`'); var href = url + region.id + '/orders/all/', next = href; var page = 1; while (!!next) { https.get(next, (res) => { LOG.info(' * * Page ' + page++ + ' responded with ' + res.statusCode); // ... 

第一个LOG.info行执行,而第二个不行。

看来你正在做一个while(!!next)循环这是你的问题的原因。 如果你显示更多的服务器代码,我们可以更精确地build议,甚至build议一个更好的代码方式。

Javascript单线程运行您的代码。 这意味着在执行任何其他事件之前,一个执行线程会运行完成。

所以,如果你这样做:

 while(!!next) { https.get(..., (res) => { // hoping this will run }); } 

然后,你的http.get()callback将永远不会被调用。 你的while循环只是一直运行下去。 只要它正在运行,从https.get()的callback永远不会被调用。 这个请求很可能已经完成了,并且在内部JS事件队列中有一个事件调用callback函数,但是直到你的while()循环完成之后,这个事件就不能被调用。 所以你有一个僵局。 while()循环正在等待别的东西运行来改变它的条件,但是在while()循环完成之前没有别的东西可以运行。

还有其他几种方法来进行串行asynchronous迭代。 一般来说,你不能使用.forEach()while()

以下是几种asynchronous循环scheme:

Node.js:你如何处理循环中的callback?

while循环与jQueryasynchronousAJAX调用

如何同步一系列的承诺?

如何使用after和each连接在下划线js中创build一个同步循环

或者,你提到的asynchronous库也有做asynchronous循环的function。

首先,几个MB的JSON有效负载并不是很大。 因此,路由处理程序代码可能需要仔细审查。

但是,要实际处理大量的JSON,可以将请求用作stream。 JSONStream (以及许多其他类似的库)允许您以一种高效的内存方式执行此操作。 您可以指定需要使用JSONPath (JSON的XPath模拟)进行处理的path,然后订阅匹配数据集的stream。

JSONStream 自述文件中的以下示例简洁地说明了这一点:

 var request = require('request') , JSONStream = require('JSONStream') , es = require('event-stream') request({url: 'http://isaacs.couchone.com/registry/_all_docs'}) .pipe(JSONStream.parse('rows.*')) .pipe(es.mapSync(function (data) { console.error(data) return data })) 

使用请求模块的streamfunction来处理大量的传入数据。 随着数据通过数据stream传输,将数据parsing为可处理的数据块,通过pipe道将数据推送出去,并引入下一个数据块。

您可能会创build一个转换stream来处理已分析的数据块,以及一个写入stream来存储数据块。

例如:

 var stream = request ({ url: your_url }).pipe(parseStream) .pipe(transformStream) .pipe (writeStream); stream.on('finish', () => { setImmediate (() => process.exit(0)); }); 

尝试创build信息streamhttps://bl.ocks.org/joyrexus/10026630