异步控制我一直想不出太好的办法,github上有一些优秀的异步流程控制库,从点赞数量上及可以看出来很优秀,本着爱吓折腾的情怀就自己写了一个异步流程控制的模块,用起来还相当清爽,之前发过一个 用异步队列控制你的异步,后来改了又改,终于改成想要的样子了。
安装
npm install queue5
使用
const queue = require('queue5');
const arr = [];
for (let i = 0; i < 100; i += 1) {
arr.push(1000 + i);
}
async function test(args) {
const result = await queue(args, 20, (item, next) => {
setTimeout(() => {
next('next'); // 通过next()传递数据
}, item);
});
console.log(result);
}
test(arr);
结果
实战
决定用这个异步队列控制一个爬虫试试,相对于python写的爬虫简直不要太清爽,首先安装爬虫所需要的工具:
npm install queue5 request cheerio
然后就是开始爬取网页了,简单的拿博客园试下手,希望大家都不要用博客园试手,可以换个网站尝试下,假设我现在有个需求,需要爬取博客园前50页的文章的标题,所以可以这样:
const queue = require('queue5');
const cheerio = require('cheerio');
const request = require('request');
const urls = [];
for (let i = 0; i < 50; i++) {
urls.push('https://www.cnblogs.com/#p' + i);
}
// 用到了async函数,请自觉升级node至7.0以上
async function main (args){
// 这里控制五个并发,不要给博客园太大压力
const titles = await queue(args, 5, function(url, next){
request(url, function(err, res, body){
if (!err) {
const $ = cheerio.load(body);
let title = $('a.titlelnk').toArray().map(function(item){
return $(item).text();
})
next(title); //通过next()将数据进行传递
}
});
});
// titles中是很多标题数组组成的一个数组,有兴趣的同学可以打印出来自己看一下
// 所以需要对titles中的数据进行处理,我希望得到一个标题组成的数组,所以就简单处理了下
let result = [];
titles.forEach(function(item){
result = result.concat(item);
});
console.log(result);
}
main(urls);
其中用到了async和await的相关知识,有不明白这部分内容的同学可以自行百度下,目前队列中对数据用next()进行传递,最终得到的结果是一个数组,由于案例中的title是一个数组,所以最终得到的结果是一个数组组成的数组,这个处理起来也很方便,看具体需求。 花了很长时间写了这么个异步队列,终于得到差不多想要的效果了。
最后
一如既往:欢迎Star和Issues https://github.com/houbean/queue5 也欢迎有疑惑或者建议的同学在评论区发表评论,我会尽力解答的。
async/await 的目的就是屏蔽回调,看到两者一块出现感觉怪怪的 控制并发可以使用promise.all 楼主的队列是用数组表示的,这就很尴尬了, 如果数组小的话用promise.all就能解决,数组大的话…我爬pixiv有几千万个异步 所以我一般使用redis做队列 以上仅为个人看法
@Yuki-Minakami受教了,确实没考虑到你说的场景;只是简单的实现了下对并发数量的精确控制,单就异步任务的并发控制来说比promise.all来说还是有点优势,不过局限性肯定也是有的,比如队列用数组表示,不过当个小工具使使还是可以的。谢谢你的意见。