我正在尝试理解回调和异步编程,但我遇到了一些麻烦。
这里有一些伪代码:
var lines = [];
var arrayOfFeedUrls = [url1,url2,...];
function scrape(url){
http.get(url, function(res) {
res.pipe(new FeedParser([options]))
.on('readable', function () {
var stream = this, item;
while (item=stream.read()) {
line = item.title;
lines.push(line);
}
});
});
});
for (i in arrayOfFeedUrls){
scrape(arrayOfFeedUrls[i];
}
console.log(lines.length);
它显然返回0,因为scrape函数是异步执行的。我理解的很多,但我尝试了许多错综复杂的方法,无法弄清楚如何正确地编写它。任何帮助/解释将不胜感激。我已经阅读了(我还在阅读)很多教程和示例,但我认为获得它的唯一方法是自己编写一些代码。如果我解决了这个问题,我会发布答案。
答案 0 :(得分:2)
您可以查看this article以了解Node中的介绍,这可能有助于您更好地了解Node中的异步编程。
就异步编程而言,async是Node用户区中非常流行的模块,它可以帮助您轻松编写异步代码。例如(未经测试的伪代码):
function scrape (done) {
http.get(url, done);
}
function parse (res, done) {
var lines = [];
res.pipe(new FeedParser([options]))
.on('readable', function () {
var stream = this, item;
while (item=stream.read()) {
line = item.title;
lines.push(line);
}
})
.on('end', function () {
done(null, lines);
});
}
function done (err, lines) {
if (err) { throw err; }
console.log(lines.length);
}
async.waterfall([scrape, parse], done);
答案 1 :(得分:1)
这取决于您是想要并行扫描还是串联扫描所有网址。
如果你要连续拍摄,你应该把它想象成这样:
从第一个网址开始。刮。在回调中,刮掉下一个url。在回调中,刮掉下一个网址。
这会给你所说的臭名昭着的回调,但至少这是原则。图书管理员喜欢async等会让人头疼不已。
答案 2 :(得分:1)
以这种方式编写异步调用时,您希望链接到最后的函数和指令(例如console.log(lines.length);
)也必须是回调函数。例如,尝试这样的事情:
var lines = [];
var arrayOfFeedUrls = [url1,url2,...];
function scrape(url){
http.get(url, function(res) {
res.pipe(new FeedParser([options]))
.on('readable', function () {
var stream = this, item;
while (item=stream.read()) {
line = item.title;
lines.push(line);
done();
}
});
});
});
for (i in arrayOfFeedUrls){
scrape(arrayOfFeedUrls[i];
}
function done () {
if (lines.length == arrayOfFeedUrls.length) {
console.log(lines.length);
}
}
您可能还想查看promises,这是回调的另一种编程风格,旨在避免回调地狱。
答案 3 :(得分:1)
不得不承认我对node.js很新,并努力克服回调的东西。在我有限的经验中,向回调函数添加一个参数可能就是诀窍。难题是,哪个参数?
在您的示例中,如果函数scrape
有一个额外的布尔“lastOne”,那么它可以调用console.log(行)本身。或者,如果它理解空url意味着停止。 然而,我不认为即便如此,因为我不确定一切都会按顺序完成。如果第二个URL需要永远,最后一个URL可能先完成,对吧??? (你可以尝试一下)。换句话说,我仍然不知道要添加哪个参数。遗憾...
似乎更可靠的是将计数器设置为urls.length,并且scrape()
每次都减少它。当计数器达到0时,它知道整个过程已完成,并且应该记录(或做任何事情)结果。我不是100%肯定在哪里宣布这个柜台。来自Java我仍然不知道什么是静态全局,什么是实例,无论......
现在,一个真正的蓝色node.jser会传递一个函数来执行任何作为scrape()
的额外参数,以便您可以执行console.log()
之外的其他操作。 :-)但我会支持零检查。
稍微详细说明,将callWhenDone
参数添加到scrape()
,然后添加(在所有嵌套中的某处!)
if (--counter <= 0)
callWhenDone (lines);
答案 4 :(得分:1)
好的,所以这就是我如何解决问题,随意评论并告诉我它是否正确。
var lines = [];
var arrayOfFeedUrls = [url1,url2,...];
function scrape(array){
var url = array.shift();
http.get(url, function(res) {
res.pipe(new FeedParser([options]))
.on('readable', function () {
var stream = this, item;
while (item=stream.read()) {
line = item.title;
lines.push(line);
}
}).on('end', function () {
if(array.length){
scrapeFeeds(array);
}
});
});
});
scrapeFeeds(array);
感谢所有的答案,我正在寻找更深入的异步,因为我有更复杂的事情要做。让我知道您对我的代码的看法,它始终有用。