我有一台Node.JS服务器,它请求来自两个Web服务器的数据:bbc.co.uk和sky.com。然后解析RSS提要,用户看到两个列表:来自BBC和天空。
这是代码。
var feed = require('feed-read');
var http = require('http');
var async = require('async');
var request = require('request');
var LIMIT = 10;
var UNABLE_TO_CONNECT = "Unable to connect.";
var BBC_URL = 'http://feeds.bbci.co.uk/news/rss.xml';
var SKY_URL = 'http://news.sky.com/feeds/rss/home.xml';
var server = http.createServer(onRequest);
server.listen(9000);
function onRequest(req, res) {
res.writeHead(200, {
'Content-Type' : 'text/html; charset=utf-8'
});
async.parallel([ function(callback) {
feed(BBC_URL, onRssFetched);
// TODO: where to call callback()?
}, function(callback) {
feed(SKY_URL, onRssFetched);
// TODO: where to call callback()?
} ], function done(err, results) {
console.log("Done");
if (err) {
throw err;
}
});
}
function onRssFetched(err, articles) {
console.log("RSS fetched");
var html = [];
if (err) {
html.push("<p>", UNABLE_TO_CONNECT = "</p>");
} else {
html.push("<ol>");
var i = 0;
articles.forEach(function(entry) {
if (i == LIMIT) {
return;
}
html.push("<li><a href='" + entry.link + "'>" + entry.title
+ "</a></li>");
i++;
});
}
console.log(html.join(""));
}
现在我不知道如何将结果添加到网页中。如果我在调用callback()
方法后立即致电feed
,callback()
将会执行,而不会等到feed
完成其工作。另一方面,我无法将callback
传递给feed
。也许这种方法是错误的,我还需要一些其他模块来进行RSS解析。
答案 0 :(得分:12)
@Maksim我知道你的原始问题包括 async 模块,但提出了另一种选择:
为什么不 流 每篇文章到客户端,而不是等待所有 RSS提要在发送回复之前返回...?
使用 async.parallel 告诉节点:
“等到我们收到回复 所有 这些新闻服务
只有 然后 (将文章组合成) 单 对客户的回应 ...“
当您等待所有响应(来自RSS新闻服务)时,这会占用每个连接客户端的内存... 浪费。
所以我没有诉诸 async 就写了我的答案。
并且,而不是等待年龄(而 async 将所有Feed合并为一个),
一旦 第一个 rss Feed返回,客户就会看到新闻!
var feed = require('feed-read'), // require the feed-read module
http = require("http"),
urls = [
"http://feeds.bbci.co.uk/news/rss.xml",
"http://news.sky.com/feeds/rss/home.xml",
"http://www.techmeme.com/feed.xml"
]; // Example RSS Feeds
http.createServer(function (req, res) {
// send basic http headers to client
res.writeHead(200, {
"Content-Type": "text/html",
"Transfer-Encoding": "chunked"
});
// setup simple html page:
res.write("<html>\n<head>\n<title>RSS Feeds</title>\n</head>\n<body>");
// loop through our list of RSS feed urls
for (var j = 0; j < urls.length; j++) {
// fetch rss feed for the url:
feed(urls[j], function(err, articles) {
// loop through the list of articles returned
for (var i = 0; i < articles.length; i++) {
// stream article title (and what ever else you want) to client
res.write("<h3>"+articles[i].title +"</h3>");
// check we have reached the end of our list of articles & urls
if( i === articles.length-1 && j === urls.length-1) {
res.end("</body>\n</html>"); // end http response
} // else still have rss urls to check
} // end inner for loop
}); // end call to feed (feed-read) method
} // end urls for loop
}).listen(9000);
主要优势:
有关此解决方案的更多细节/说明
见:https://github.com/nelsonic/node-parse-rss
答案 1 :(得分:1)
不,你不需要另一个图书馆。但您需要做的是将callback
移交给feed
函数而不是onRssFetched
。这样,使用async.parallel
变量将单个RSS Feed移交给result
调用中的最终回调。
在这个变量中,您可以同时访问这两个RSS源,并且可以使用它们执行任何操作。
所以,基本上你的逻辑需要是:
async.parallel({
bbc: function (callback) {
feed(BBC_URL, callback);
},
sky: function (callback) {
feed(SKY_URL, callback);
}
}, function (err, result) {
if (err) {
// Somewhere, something went wrong…
}
var rssBbc = result.bbc,
rssSky = result.sky;
// Merge the two feeds or deliver them to the client or do
// whatever you want to do with them.
});
就是这样: - )。
答案 2 :(得分:0)
为了放大@nelsonic的答案(足够让我觉得这保证了它自己的答案),feed-parse
已经异步处理了。从本质上讲,它仍然在http.request上运行。如果你查看代码,你会看到你甚至可以直接传递一个URL数组,它会遍历它们,但是它使用了更多的“async.eachSeries”方法,其中下一个调用只发生在前一个调用之后完成,看起来不是你想要的。
如果您真的想在处理之前等待调用先完成,那么最好异步缓冲数据,然后在所有URL完成后使用下划线_.after()
运行。
但很可能,你真正想要做的事情(除非你只是想找一个尝试异步的例子)是@ nelsonic的答案。
答案 3 :(得分:0)
理想情况下,我会流式传输rss数据,而不是在内存中聚合。 @nelsonic解释了解决这个问题的正确方法。
但是,如果我们要让您的代码运行,请考虑以下代码:
var util = require('util');
var http = require('http');
var async = require('async');
var feed = require('feed-read');
var request = require('request');
var LIMIT = 10;
var UNABLE_TO_CONNECT = 'Unable to connect.';
var BBC_URL = 'http://feeds.bbci.co.uk/news/rss.xml';
var SKY_URL = 'http://news.sky.com/feeds/rss/home.xml';
var server = http.createServer(onRequest);
server.listen(9000);
function onRequest(req, res) {
util.log('Request recieved!');
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
});
async.parallel({
bbc: function (callback) {
feed(BBC_URL, function (err, articles) {
var html = onRssFetched(err, articles);
callback(err, html);
});
},
sky: function (callback) {
feed(SKY_URL, function (err, articles) {
var html = onRssFetched(err, articles);
callback(err, html);
});
}
}, done);
function done(err, results) {
util.log('Received results: ' + Object.keys(results).join(','));
if (!err && results) {
var entry, html;
for (entry in results) {
html = results[entry];
res.write(html.join(''));
}
util.log('Send complete!');
res.end();
} else {
console.log(err || 'no data in results');
res.end('Unable to process your request');
}
}
}
function onRssFetched(err, articles) {
// limit number of articles;
articles = articles.slice(0, LIMIT);
var html = [];
if (err) {
html.push('<p>', UNABLE_TO_CONNECT = '</p>');
} else {
html.push('<ol>');
articles.forEach(function (entry) {
html.push('<li><a href="' + entry.link + '">' + entry.title + '</a></li>');
});
html.push('</ol>');
}
return html;
}
// -- Test Code ---------------------------------------------------------
if (require.main === module) {
(function () {
var req, res = {
writeHead: console.log,
write: console.log,
end: console.log
};
// onRequest(req, res);
})();
}
如果您遇到任何问题,请告诉我。