Node.js의 내부 동작에 익숙하지 않지만 너무 많은 함수 호출을 할 때 '최대 호출 스택 크기 초과'오류가 발생한다는 것을 알고 있습니다.Node.js에서 많은 데이터가 스택 크기를 초과 할 수 있습니까?
나는 링크를 따라갈 거미를 만들고있어 크롤링 된 URL의 무작위 수 이후에 이러한 오류가 발생하기 시작했습니다. 이 경우 노드는 스택 추적을주지 않지만 재귀 오류가없는 것은 확실합니다.
내가 URL을 가져 request을 사용하고나는 이 인출 된 HTML을 분석하고 새로운 링크를 감지 cheerio를 사용하여했다. 스택 오버플로는 항상 cheerio 내부에서 발생합니다. htmlparser2에 대한 cheerio를 바꿀 때 오류가 사라졌습니다. Htmlparser2는 전체 문서를 파싱하고 트리를 구성하는 대신 열려있는 각 태그에 이벤트를 방출하기 때문에 훨씬 가볍습니다.
내 이론은 cheerio가 스택의 모든 메모리를 먹었지만 이것이 가능할 지 확신하지 못합니다.
여기 내 코드의 단순화 된 버전입니다 (단지 읽기 위해, 그것은 실행되지 않습니다이다) : 당신이 거기에가는 몇 가지 재귀를 가지고 같은
var _ = require('underscore');
var fs = require('fs');
var urllib = require('url');
var request = require('request');
var cheerio = require('cheerio');
var mongo = "This is a global connection to mongodb.";
var maxConc = 7;
var crawler = {
concurrent: 0,
queue: [],
fetched: {},
fetch: function(url) {
var self = this;
self.concurrent += 1;
self.fetched[url] = 0;
request.get(url, { timeout: 10000, pool: { maxSockets: maxConc } }, function(err, response, body){
self.concurrent -= 1;
self.fetched[url] = 1;
self.extract(url, body);
});
},
extract: function(referrer, data) {
var self = this;
var urls = [];
mongo.pages.insert({ _id: referrer, html: data, time: +(new Date) });
/**
* THE ERROR HAPPENS HERE, AFTER A RANDOM NUMBER OF FETCHED PAGES
**/
cheerio.load(data)('a').each(function(){
var href = resolve(this.attribs.href, referer); // resolves relative urls, not important
// Save the href only if it hasn't been fetched, it's not already in the queue and it's not already on this page
if(href && !_.has(self.fetched, href) && !_.contains(self.queue, href) && !_.contains(urls, href))
urls.push(href);
});
// Check the database to see if we already visited some urls.
mongo.pages.find({ _id: { $in: urls } }, { _id: 1 }).toArray(function(err, results){
if(err) results = [];
else results = _.pluck(results, '_id');
urls = urls.filter(function(url){ return !_.contains(results, url); });
self.push(urls);
});
},
push: function(urls) {
Array.prototype.push.apply(this.queue, urls);
var url, self = this;
while((url = self.queue.shift()) && this.concurrent < maxConc) {
self.fetch(url);
}
}
};
crawler.fetch('http://some.test.url.com/');
나는 치어로 같은 오류가 발생했습니다. 당신이 원인을 알아 냈습니까? – Lloyd
불행히도 없습니다. 프로젝트의 경우 htmlparser2 만 사용하면 충분했으며 오류는 발생하지 않았습니다. – disc0dancer
좋아 .. 결국 수동으로 html 텍스트를 조작해야만 cheerio에 전달하기 전에 파싱했는데 걱정하지 않은 모든 마크 업을 제거했다. – Lloyd