2016-06-04 1 views
1

현재로서는 을 매우 개의 API (특히 this)에서 가져온 대규모 JSON 개체 (여러 가지 요인에 따라 몇 MB 이상 될 수 있음)를 요청하려고합니다. 그러나 문제는 NodeJS가 무엇인가를 영원히 받아 들인 다음 메모리가 부족한 것입니다. 즉, 응답 콜백의 첫 번째 행은 실행되지 않습니다.NodeJS http 및 매우 큰 응답 본문

각 항목을 개별적으로 요청할 수는 있지만 엄청난 양의 요청입니다. 새로운 API의 개발자를 인용하려면 다음과 같이하십시오.

지금까지 Tranquility에 대한 모든 시장 주문을 받고 싶다면 지역마다 모든 유형을 개별적으로 요청해야했습니다. 일반적으로 50+ 개 지역에 13,000 개 이상의 유형이 곱해집니다. 단지 13,000 개의 유형과 50 개의 지역 일지라도 모든 시장 정보를 얻기 위해서는 650,000 건의 요청이 필요합니다. 그리고 5 분 캐시 창에서 모든 데이터를 가져 오려면 초당 거의 2,200 개의 요청이 필요합니다.

분명히, 그것은 좋은 생각이 아닙니다.

을 나중에 사용하기 위해 다시 설정하려고 시도한 다음 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 행은 실행되지만 두 번째 행은 실행되지 않습니다.

+0

응답이 몇 MB 경우에 정보를

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

시도? 나는 그 질문부터 시작하고 싶을 것 같은데. 방금 JSON 응답을 측정했는데 6.23MB였습니다. – jfriend00

+0

문서는 크기가 "여러"MB가 될 수 있음을 경고합니다. 어느 쪽이든, 메모리 및 실행에 걸리는 시간에는 여전히 문제가 있습니다. 브라우저에서 링크를 방문하는 데는 오랜 시간이 걸리지 않습니다. – NukesForKids

+0

node.js 코드를 알려주십시오. 여기 브라우저에서도 잘 작동합니다. https://jsfiddle.net/jfriend00/qscyqt7d/ – jfriend00

답변

4

문제의 원인 인 while(!!next) 루프를 수행하고있는 것으로 보입니다. 더 많은 서버 코드를 보여 주면 우리는 더 정확하게 조언하고 심지어 코드를 작성하는 더 좋은 방법을 제안 할 수 있습니다.

자바 스크립트는 단일 스레드로 코드를 실행합니다. 즉, 다른 이벤트를 실행하기 전에 하나의 실행 스레드가 완료까지 실행됩니다.

그래서, 당신이 할 경우 :

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

는 그런 http.get()로 콜백

를 호출되지 얻을 않습니다. while 루프는 계속 영원히 계속 실행됩니다. 실행중인 동안에는 https.get()의 콜백을 호출 할 수 없습니다. 이 요청은 완료된 지 오래되었으며 이벤트가 내부 JS 이벤트 대기열에 앉아 콜백을 호출하지만, while() 루프가 끝날 때까지 해당 이벤트를 호출 할 수 없습니다. 그래서 교착 상태에 빠졌습니다. while() 루프는 상태를 변경하기 위해 다른 것을 실행하기를 기다리고 있지만 while() 루프가 완료 될 때까지는 아무 것도 실행될 수 없습니다.

직렬 비동기 반복을 수행하는 몇 가지 다른 방법이 있습니다. 일반적으로 .forEach() 또는 while()을 사용할 수 없습니다.

Node.js: How do you handle callbacks in a loop?

While loop with jQuery async AJAX calls

How to synchronize a sequence of promises?

How to use after and each in conjunction to create a synchronous loop in underscore js

또는, 당신은 또한 비동기 작업을 수행하는 기능을 가지고 언급 비동기 라이브러리 : 여기

는 비동기 루프에 대한 몇 가지 계획입니다 루핑.

+0

iterating 비동기 작업에 대한 몇 가지 참조가 추가되었습니다. – jfriend00

+0

이것은 허용 된 대답이어야합니다. 누군가가 큰 json 페이로드를 처리하는 문제를 실제로 찾고있는 Google을 통해이 질문을 발견하는 경우를 대비해서 나는 내 것을 떠난다. – lorefnon

2

우선, 몇 MB의 json 페이로드가 정확히 거대하지 않습니다. 따라서 라우트 핸들러 코드는 면밀한 조사가 필요합니다.

그러나 엄청난 양의 JSON을 실제로 처리하려면 요청을 스트림으로 사용할 수 있습니다. JSONStream (많은 다른 유사한 라이브러리와 함께)을 사용하면 메모리 효율적인 방식으로이 작업을 수행 할 수 있습니다. JSONPath (JSON 용 XPath 아날로그)을 사용하여 처리해야하는 경로를 지정한 다음 일치하는 데이터 세트에 대한 스트림을 구독 할 수 있습니다. JSONStream의 README에서 다음 예

이 간결 보여

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 
    })) 
+0

큰 JSON처럼 보이지 않습니다. 실제로 여기에서는 전혀 문제가되지 않습니다. 무한 루프와 비동기 루핑의 문제 일 가능성이 큽니다. – jfriend00

0

수신 대량의 데이터를 처리하도록 요청 모듈의 스트림 기능을 사용한다. 데이터가 스트림을 통해 들어 오면 처리 할 수있는 데이터 청크로 구문 분석하고 파이프를 통해 데이터를 밀어 넣은 다음 데이터 덩어리를 가져옵니다.

구문 분석 된 데이터 청크를 조작하기 위해 변환 스트림을 만들고 데이터 청크를 저장하기 위해 쓰기 스트림을 생성 할 수 있습니다. 예를 들어

: 메모리가 부족하는 이유를 작성 스트림 https://bl.ocks.org/joyrexus/10026630