原例子地址:https://github.com/alsotang/node-lessons/tree/master/lesson4
例子中使用eventproxy实现一个异步获取网页内容,刚接触Promise所以就尝试用Promise来修改代码,同时实现里课程中的tiao挑战题:
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/';
function fetchUrl(url) {
return new Promise((resolve, reject) => {
superagent.get(url).end(function(err, res){
resolve([url, res.text])
})
})
}
function fetchAuthor(item, url) {
return new Promise((resolve, reject) => {
if( url === undefined ) {
reject(item)
} else {
superagent.get(url).end(function(err, res){
resolve([item,res.text]);
});
}
});
}
superagent.get(cnodeUrl)
.end(function (err, res) {
if (err) {
return console.error(err);
}
var topicUrls = [];
var $ = cheerio.load(res.text);
// 获取首页所有的链接
$('#topic_list .topic_title').each(function (idx, element) {
var $element = $(element);
var href = url.resolve(cnodeUrl, $element.attr('href'));
topicUrls.push(href);
});
var items = [];
topicUrls.forEach(function (topicUrl) {
fetchUrl(topicUrl).then(result => {
var topicUrl = result[0];
var topicHtml = result[1];
let $ = cheerio.load(topicHtml);
let item = {
title: $('.topic_full_title').text().trim(),
href: topicUrl,
comment1: $('.reply_content').eq(0).text().trim(),
author1: $('.reply_author').eq(0).text().trim(),
score1: null,
}
let authorHref = $('.reply_author').attr('href');
if( authorHref !== undefined ) {
let href = url.resolve(cnodeUrl,authorHref);
return fetchAuthor(item,href);
} else {
return fetchAuthor(item,undefined);
}
}).then(result => {
let item = result[0];
let authorHtml = result[1];
let $ = cheerio.load(authorHtml);
item.score1 = $('.user_profile .unstyled .big').eq(0).text();
console.log('-----')
console.log(item)
items.push(item);
}).catch(item => {
console.log('=====')
console.log(item)
items.push(item);
})
});
// var fetchs = [];
// topicUrls.forEach(function (topicUrl) {
// fetchs.push(fetchUrl(topicUrl));
// });
// Promise.all(fetchs).then(fetchResults => {
// fetchResults.forEach(result => {
// var topicUrl = result[0];
// var topicHtml = result[1];
// var $ = cheerio.load(topicHtml);
// let item = {
// title: $('.topic_full_title').text().trim(),
// href: topicUrl,
// comment1: $('.reply_content').eq(0).text().trim(),
// author1: $('.reply_author').eq(0).text().trim(),
// }
// items.push(item);
// // console.log(item)
// });
// console.log('final:');
// console.log(items);
// })
// console.log(topicUrls);
});
主要思路就是获取了主页面的主题之后,对每个主题生成一个promise(可以理解为一个promise就是访问一个主题),promise的resolve函数内处理具体主题内的内容(评论、主题标题等)。
挑战题中的第一条评论的用户以及积分是需要再此访问用户信息才能得到的
let authorHref = $('.reply_author').attr('href');
上面这段代码就是获取了符合要求用户的地址。
接下来就是再次访问了,再写一个promise去访问,同样在resolve函数内处理得到的数据。
最后一块注释掉的是用Promise.all尝试的另一种方法