新手求教,node-lessons,lesson4的挑战
发布于 4 年前 作者 dilingchen 5549 次浏览 来自 问答

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'
  }
]
回到顶部