Stack上有几个类似的问题,但我无法得到任何适合我的答案,我对Node和异步编程的想法都很陌生,所以请耐心等待。
我正在构建一个目前有四个步骤的刮刀:
img src
href
,从所述href
检索dom并重复步骤#2。img src
都放入数组并返回这是代码。 getLinks
可以异步调用,但其中的while
循环当前不能:
function scrape(url, oncomplete) {
console.log("Scrape Function: " + url);
request(url, function(err, resp, body) {
if (err) {
console.log(UHOH);
throw err;
}
var html = cheerio.load(body);
oncomplete(html);
}
);
}
function getLinks(url, prodURL, baseURL, next_select) {
var urls = [];
while(url) {
console.log("GetLinks Indexing: " + url);
var html = scrape(url, function(data) {
$ = data;
$(prodURL).each(function() {
var theHref = $(this).attr('href');
urls.push(baseURL + theHref);
}
);
next = $(next_select).first().attr('href');
url = next ? baseurl + next : null;
}
);
}
console.log(urls);
return urls;
}
目前这进入了无限循环而没有刮擦任何东西。如果我将url = next ? baseurl + next : null;
置于回调之外,则会出现"next" is not defined
错误。
关于如何重新设计它以使其对节点友好的任何想法?似乎,根据这个问题的本质,它需要阻塞,不是吗?
答案 0 :(得分:1)
这是一种常见的模式,您希望执行循环但使用带回调的异步函数。由于您不能等待异步函数,因此不能简单地使用while循环。
一种解决方案是使用“堆栈”(或数组)。使用您要处理的初始元素填充它。当您发现要处理的更多元素时,将它们添加到此堆栈中。并递归调用函数递增索引以进行处理,直到索引超过数组的长度。
e.g。
function do_scrape( stack, this_url, callback ) {
// get list of URLs from webpage at this_url
...
stack.push( new_url ); // adding new element to array
...
...
callback(); // process callback
}
function process_stack( stack_of_urls, idx ) {
var this_url = stack_of_urls[idx];
do_scrape(
stack_of_urls,
this_url,
function () {
if ( idx + 1 < stack_of_urls.length ) {
process_stack( stack_of_urls, (idx + 1) );
} else {
process.exit( 0 );
}
}
);
}
var stack_of_urls = [ "http://www.yahoo.com/" ];
process_stack( stack_of_urls, 0 ); // start from index zero
注意有很多方法可以解决这个问题。为了提高效率,您可以从堆栈中删除已处理的元素。您还可以选择是从头到尾,还是从头到尾等处理堆栈。最后请注意,如果您不在do_scrape
函数中调用异步函数,那么您将拥有一个紧密的循环回调,其中node.js将中止抱怨堆栈太大。