Javascript 节点,异步编程,回调地狱
我试图理解回调和异步编程,但我遇到了一些麻烦 下面是一些伪代码:Javascript 节点,异步编程,回调地狱,javascript,node.js,asynchronous,Javascript,Node.js,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
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函数是异步执行的。我明白很多,但我已经尝试了很多复杂的方法,不知道如何正确地编写它。如有任何帮助/解释,将不胜感激。我已经读过(现在还在读)很多教程和例子,但我认为我获得它们的唯一方法是自己编写一些代码。如果我解决了这个问题,我会发布答案。您可以查看Node中的介绍,这可能会帮助您更好地理解Node中的异步编程
就异步编程而言,它是节点用户区中非常流行的模块,可以帮助您轻松地编写异步代码。例如(未测试的伪代码):
这取决于您是希望并行还是串行地刮取所有URL 如果你要连续做,你应该这样想: 从第一个url开始。刮在回调中,刮取下一个url。在回调中,刮取下一个url
这将给你所说的臭名昭著的回调带来地狱,但这至少是原则。像async之类的库消除了很多麻烦。以这种方式编程异步调用时,您希望链接到末尾的函数和指令,例如
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);
}
}
您可能还想研究回调的另一种编程风格,其目的是避免回调地狱。必须承认,我对node.js非常陌生,正在努力摸索回调的东西。根据我有限的经验,在回调函数中再添加一个参数可能是一个技巧。困难的问题是,哪个参数
在您的示例中,如果函数scrape
有一个额外的布尔值“lastOne”,那么它可以调用console.log(行)。或者,如果它理解空url意味着停止。然而,我认为即使这样也行不通,因为我不确定一切都会按顺序完成。如果第二个URL需要很长时间,最后一个可能会先完成,对吗???(你可以试试看)。换句话说,我仍然不知道要添加哪个参数。对不起
似乎更可靠的方法是将计数器设置为url.length,并为scrap()
每次递减。当计数器达到0时,它知道整个过程已经完成,它应该记录(或执行任何操作)结果。我不能百分之百确定在哪里申报这个柜台。来自Java的我仍然不知道什么是静态全局,什么是实例,无论什么
现在,一个真正的blue node.jser将向doWhatever传递一个函数,作为scrape()
的额外参数,这样您就可以执行console.log()
:-)以外的操作了但我愿意接受零的支票
稍微详细说明一下,将callWhenDone
参数添加到scrap()
,然后添加(在所有嵌套中的某个地方!!!)
if(--counter好的,下面是我如何解决这个问题的,请随意评论并告诉我它是否正确
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);
感谢所有的答案,我正在更深入地研究异步,因为我有更复杂的事情要做。让我知道你对我的代码的看法,它总是有用的。看看承诺。我认为它们是避免回调地狱的最优雅的方式。虽然异步库可以解决这个问题,但它没有解释应该如何解决。PromISE很花哨,但命名和取消嵌套回调将大大减少混乱和混乱;只需传递将关闭的内容即可,这有助于记录您的过程。这至少是承诺的一半,但需要更少的努力和学习。简言之,如果char(()正好出现在chars“函数”之后,你做错了。我不认为lines.length与url.length匹配,因为每个url可能有多行。(我认为)。但我认为你的思路是正确的-请查看我的答案并发表评论,如果你认为这是一种改进(或不是),请检查我的答案,里面有一点你的:)
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);