4

i'm trying to understand callbacks and async programming, but I'm having a bit of trouble.

here's some pseudocode :

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);

It obviously returns 0, as the scrape function is executed asynchronously. I understand that much, but I've tried many intricated ways and can't figure out how to write it properly. Any help/explanation would be greatly appreciated. I've read (and I'm still reading) a lot of tutorials and examples, but I think the only way for me to get it is to write some code myself. If I solve this I'll post the answer.

4

5 回答 5

2

您可能想查看这篇文章以了解 Node 的介绍,这可能会帮助您更好地理解 Node 中的异步编程。

就异步编程而言,异步是 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);
于 2013-10-28T16:17:06.893 回答
1

不得不承认我对 node.js 很陌生,并且很难理解回调的东西。以我有限的经验,向回调函数添加一个参数可能是诀窍。难题是,哪个参数?

在您的示例中,如果该函数scrape有一个额外的布尔值“lastOne”,那么它可以调用 console.log(lines) 本身。或者,如果它理解空 url 意味着停止。 但是,我认为即使这样也行不通,因为我不确定一切都会按顺序完成。如果第二个 URL 永远需要,最后一个可能会先完成,对吧???(你可以试试)。换句话说,我仍然不知道要添加哪个参数。对不起...

似乎更可靠的是为 urls.length 设置一个计数器,并且scrape()每次都将其递减。当计数器达到 0 时,它知道整个过程已经完成,它应该记录(或做任何事情)结果。我不是 100% 确定在哪里声明这个柜台。来自Java我仍然不知道什么是静态全局,什么是实例,无论如何......

现在,一个真正的 node.jser 会将一个函数作为一个额外的参数传递给 doWhatever scrape(),这样你就可以做除console.log(). :-) 但我愿意接受零支票。

稍微详细一点,添加一个callWhenDone参数scrape(),然后添加(在所有嵌套中的某个地方!!!)

if (--counter <= 0)
  callWhenDone (lines);
于 2013-10-28T18:42:20.703 回答
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);

感谢所有答案,我正在更深入地研究异步,因为我有更复杂的事情要做。让我知道您对我的代码的看法,它总是有用的。

于 2013-10-28T19:52:07.893 回答
1

这取决于您是要并行还是串行抓取所有 url。

如果你要连续做,你应该这样想:

从第一个网址开始。刮。在回调中,抓取下一个 url。在回调中,抓取下一个 url。

这会给你所说的臭名昭著的回调地狱,但至少这是原则。像异步等这样的图书馆消除了很多头痛。

于 2013-10-28T16:20:18.440 回答
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,这是回调的另一种编程风格,旨在避免回调地狱。

于 2013-10-28T16:20:31.940 回答