我正在尝试从存储在数组中的一堆HTML页面中提取字符串。我有以下代码:
const jsdom = require('jsdom')
desc('Import pages');
task('handleSpots', [], function (params) {
allSpots.forEach(function(spotUrl){
handleSpot(spotUrl)
})
});
function handleSpot (href) {
jsdom.env(
href,
["http://code.jquery.com/jquery.js"],
function (err, window) {
if (err) {
console.log(host+href+" "+err)
return
}
const data = {url: host+href}
data['name'] = window.$("h1.wanna-item-title-title a").text()
console.log(data['name'])
window.close()
}
);
}
allSpots数组中大约有600个网址。当我运行这个时,我得到了一堆错误:
/the_hook/index.html Error: read ECONNRESET
这发生在一堆网址上,显示了一些名字,最后我得到了这个错误。
<--- Last few GCs --->
80660 ms: Scavenge 1355.3 (1460.0) -> 1355.3 (1460.0) MB, 2.3 / 0 ms (+ 1.4 ms in 1 steps since last GC) [allocation failure] [incremental marking delaying mark-sweep].
82149 ms: Mark-sweep 1355.3 (1460.0) -> 1354.8 (1460.0) MB, 1488.7 / 0 ms (+ 2.8 ms in 2 steps since start of marking, biggest step 1.4 ms) [last resort gc].
83657 ms: Mark-sweep 1354.8 (1460.0) -> 1354.6 (1460.0) MB, 1508.2 / 0 ms [last resort gc].
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x38f1b4237339 <JS Object>
1: create [native v8natives.js:~755] [pc=0x22e6902f1923] (this=0x38f1b4236b61 <JS Function Object (SharedFunctionInfo 0x38f1b4236ad1)>,an=0x1590d58f6941 <an Object with map 0x1b19e3c1e251>,aD=0x38f1b4204131 <undefined>)
2: arguments adaptor frame: 1->2
3: createImpl [/Users/craig/Programming/node_wannasurf_importer/node_modules/jsdom/lib/jsdom/living/generated/Text.js:~90] [pc=0x22e...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Abort trap: 6
仅当allSpots数组中有超过125个项目时才会发生这种情况。少于此,一切正常。
我对节点很新,但我假设Javascript试图同时获取太多这些页面并最终耗尽内存。理想情况下,我可以写出处理100的东西,等到完成后再转到下一个100。
我试过这个: async.eachLimit(allSpots,100,handleSpot) 但那只能处理前100个然后停止。
我也尝试过: async.eachSeries(allSpots,handleSpot) 但这只涉及第一个网址并停止。
我有点死路一条,所以我真的很感激任何人都可以给我的建议。 谢谢,
克雷格
答案 0 :(得分:1)
我决定放弃jsdom并用cheerio和https替换它,以便我可以对请求过程有更多的控制权。然后我研究了如何同步请求每个URL(在请求上使用on(&#39; end&#39;))然后开始在循环中处理url,因此循环迭代的次数是并发进程的数量
以下是代码:
const https = require('https');
const cheerio = require('cheerio')
desc('Import pages');
task('handleSpots', [], function (params) {
var totalLoop = 10;
for( var i = 0; i < totalLoop; i++ ) {
handleSpotAndNext()
}
});
function handleSpotAndNext() {
spot = allSpots.pop()
https.get(spot,function(res){
var chunks = '';
res.on('data',function(d){
chunks += d;
});
res.on('end',function(){
console.log(spotData(chunks, spot))
if(allSpots.length){
handleSpotAndNext();
}
})
})
}
function spotData(spotHtml, url) {
$ = cheerio.load(spotHtml)
const data = {url: url}
data['name'] = $("h1.wanna-item-title-title a").text()
return data
}
这就是我想出来的,但是如果你看到这个并且可以想到更优雅的解决方案,那么很高兴收到你的来信。