新手求教,node-lessons,lesson4的挑战
lesson4中的挑战需要拿到用户在 cnode 社区的积分值,需要异步访问用户的主页,拿到积分后再组成最后的返回值。 topics.map 是个同步方法,不知道如何在里面实现异步调用,再回调。node.js新手入门,对callback的用法还不太理解,网上找到一个如何在map中调用异步函数的例子https://futurestud.io/tutorials/node-js-how-to-run-an-asynchronous-function-in-array-map,但是套进来还是不对的。求指教。
ep.after('topic_html', topicUrls.length, function (topics) {
const promises = topics.map(async topicPair => {
var topicUrl = topicPair[0];
var topicHtml = topicPair[1];
var $ = cheerio.load(topicHtml);
var title= $('.topic_full_title').text().trim();
var comment1 = $('.reply_area').first();
var author1 = $(comment1).find('div.user_info').find('a.reply_author');
var author1Href = url.resolve(cnodeUrl, $(author1).attr('href'));
var comment1Text = $(comment1).find('div.reply_content').children().first().text().trim();
var author1Name = $(author1).text().trim();
const userScore = await superagent.get(author1Href)
.end(function (err, res) {
if (err) {
return console.error(err);
}
console.log('fetch ' + author1Href + ' successful');
var $ = cheerio.load(res.text);
return $('.user_profile').find('span.big').text().trim();
})
return {
title: title,
href: topicUrl,
comment1: comment1Text,
author1: author1Name,
score1: userScore,
}
})
// wait until all promises resolve
const results = await Promise.all(promises)
console.log('final:');
console.log(results);
});
1 回复
用两个ep.after解决了这个问题 完整代码
var eventproxy = require('eventproxy');
var superagent = require('superagent');
var cheerio = require('cheerio');
// url 模块是 Node.js 标准库里面的
// http://nodejs.org/api/url.html
var url = require('url');
var cnodeUrl = 'https://cnodejs.org/';
var goodTopicUrl = cnodeUrl+ '?tab=good'
superagent.get(goodTopicUrl)
.end(function (err, res) {
if (err) {
return console.error(err);
}
var topicUrls = [];
var $ = cheerio.load(res.text);
var count=0;
// 获取首页所有的链接
$('#topic_list .topic_title').each(function (idx, element) {
var $element = $(element);
// $element.attr('href') 本来的样子是 /topic/542acd7d5d28233425538b04
// 我们用 url.resolve 来自动推断出完整 url,变成
// https://cnodejs.org/topic/542acd7d5d28233425538b04 的形式
// 具体请看 http://nodejs.org/api/url.html#url_url_resolve_from_to 的示例
var href = url.resolve(cnodeUrl, $element.attr('href'));
if(count<5){
topicUrls.push(href);
}
count++;
});
// 得到 topicUrls 之后
// 得到一个 eventproxy 的实例
var ep = new eventproxy();
// 命令 ep 重复监听 topicUrls.length 次(在这里也就是 5 次) `topic_html` 事件再行动
ep.after('topic_html', topicUrls.length, function (topics) {
// topics 是个数组,包含了 5 次 ep.emit('topic_html', pair) 中的那 5 个 pair
// 接下来都是 jquery 的用法了
topics = topics.map(function (topicPair) {
var topicUrl = topicPair[0];
var topicHtml = topicPair[1];
var $ = cheerio.load(topicHtml);
var title= $('.topic_full_title').text().trim();
var comment1 = $('.reply_area').first();
var author1 = $(comment1).find('div.user_info').find('a.reply_author');
var author1Href = url.resolve(cnodeUrl, $(author1).attr('href'));
var comment1Text = $(comment1).find('div.reply_content').children().first().text().trim();
var author1Name = $(author1).text().trim();
return ([author1Href, {
title: title,
href: topicUrl,
comment1: comment1Text,
author1: author1Name,
}]);
});
topics.forEach(function (topicPair) {
var authorHref = topicPair[0];
var topic = topicPair[1];
superagent.get(authorHref)
.end(function (err, res) {
console.log('fetch ' + authorHref + ' successful');
var $ = cheerio.load(res.text);
var userScore = $('.user_profile').find('span.big').first().text().trim();
topic['score1'] = userScore;
ep.emit('topic_final', topic);
});
});
});
ep.after('topic_final', topicUrls.length, function (results) {
console.log('final:');
console.log(results);
});
topicUrls.forEach(function (topicUrl) {
superagent.get(topicUrl)
.end(function (err, res) {
console.log('fetch ' + topicUrl + ' successful');
ep.emit('topic_html', [topicUrl, res.text]);
});
});
});
完整输出
fetch https://cnodejs.org/topic/5533dd6e9138f09b629674fd successful
fetch https://cnodejs.org/topic/5e11ea064bea432607fcced5 successful
fetch https://cnodejs.org/topic/5c38830c3898674067a7e3a4 successful
fetch https://cnodejs.org/topic/5e16978581adfe260207a8c1 successful
fetch https://cnodejs.org/topic/56ef3edd532839c33a99d00e successful
fetch https://cnodejs.org/user/yuu2lee4 successful
fetch https://cnodejs.org/user/Dengshen successful
fetch https://cnodejs.org/user/Hoooxz successful
fetch https://cnodejs.org/user/i5ting successful
fetch https://cnodejs.org/user/zhennann successful
final:
[
{
title: '精华\n\n\n\n 我也给CNode社区做了个PWA',
href: 'https://cnodejs.org/topic/5c38830c3898674067a7e3a4',
comment1: '赞',
author1: 'yuu2lee4',
score1: '2800'
},
{
title: '精华\n\n\n\n 浅谈cnode社区如何防止csrf攻击',
href: 'https://cnodejs.org/topic/5533dd6e9138f09b629674fd',
comment1: '学习了',
author1: 'Dengshen',
score1: '170'
},
{
title: '精华\n\n\n\n 前端资源教程',
href: 'https://cnodejs.org/topic/56ef3edd532839c33a99d00e',
comment1: '感谢大神分享!\n来自酷炫的 CNodeMD',
author1: 'Hoooxz',
score1: '105'
},
{
title: '置顶\n\n\n\n 2020年1月11日Node party@北京成功举办,附照片、视频和ppt',
href: 'https://cnodejs.org/topic/5e16978581adfe260207a8c1',
comment1: '本次活动感谢talkding data支持场地',
author1: 'i5ting',
score1: '21910'
},
{
title: '精华\n\n\n\n Babel 的工程化实现',
href: 'https://cnodejs.org/topic/5e11ea064bea432607fcced5',
comment1: '感谢分享,提供了非常好的学习指引👍',
author1: 'zhennann',
score1: '300'
}
]