节点,asynchronous编程,callback地狱

我试图理解callback和asynchronous编程,但我有一些麻烦。

这是一些伪代码:

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,因为刮擦function是asynchronous执行的。 我非常了解,但是我尝试了许多错综复杂的方法,无法弄清楚如何正确书写。 任何帮助/解释将不胜感激。 我已经阅读了许多教程和示例(但我仍然在阅读),但是我认为获得它的唯一方法是自己编写一些代码。 如果我解决这个问题,我会发布答案。

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

就asynchronous编程而言, asynchronous是Node用户空间中非常stream行的模块,可以帮助您轻松编写asynchronous代码。 例如(未经testing的伪代码):

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

这取决于如果你想平行或串联刮所有的URL。

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

从第一个url开始。 刮。 在callback中,刮下一个url。 在callback中,刮下下一个url。

这会给你所说的臭名昭着的回拨地狱,但至less这是原则。 像asynchronous等图书馆去除了很多头痛。

当以这种方式编程asynchronous调用时,需要链接到最后的函数和指令,如console.log(lines.length); ,也必须是callback。 所以举个例子,尝试这样的事情:

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

你也可能想要看看承诺 ,一种替代编程风格的callback,其目的是避免callback地狱。

不得不承认,我对node.js非常陌生,并且努力想要回收这些东西。 在我有限的经验中,向callback函数中添加一个参数可能是个诀窍。 难的问题是,哪个参数?

在你的例子中,如果函数scrape有一个额外的boolean“lastOne”,那么它可以调用console.log(lines)本身。 或者,如果它明白空url意味着停止。 不过,我认为即使这样做也行得通 ,因为我不确定一切都会顺利完成。 如果第二个URL永远占满,最后一个可能会先完成,正确的? (你可以试试)。 换句话说,我还不知道要添加哪个参数。 抱歉…

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

现在,一个真正的蓝色node.jser会传递一个函数来作为scrape()一个额外的参数,这样你就可以做一些除了console.log()以外的事情。 :-)但是,我会解决检查零。

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

 if (--counter <= 0) callWhenDone (lines); 

好的,这是我如何解决问题,随时发表评论,并告诉我是否正确。

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

感谢所有的答案,我越来越深入asynchronous,因为我有更复杂的东西要做。 让我知道你对我的代码的看法,它总是有用的。