async.mapLimit 并发请求限制的一点实践
程序员文章站
2022-05-13 20:53:03
...
前言
上回参考《使用 eventproxy 控制并发》学习未能解决网站对并发请求进行限制的问题。这回继续学习《使用 async 控制并发》,目标是输出 CNode(https://cnodejs.org/ ) 社区首页的所有(40个)主题的标题,链接和第一条评论。
一个简单的callback实例
function add_callback(p1, p2 ,callback) {
var my_number = p1 + p2;
callback(my_number);
}
add_callback(5, 15, function(num){
console.log("call " + num);
});
//call 20
add_callback函数的第三个参数是回调函数。当函数执行时,传递的结果作为callback的参数。
async.mapLimit
async是一个流程控制工具包,提供了直接而强大的异步功能。基于Javascript为Node.js设计,同时也可以直接在浏览器中使用。
async异步流程控制模式包括,串行(series),并行(parallel),瀑布(waterfall)等。
async主要实现了三个部分的流程控制功能:
- 集合: Collections
- 流程控制: Control Flow
- 工具类: Utils
这次用到的是集合中的mapLimit(coll, limit, iteratee, callback opt)
每次以指定的最大limit
数执行异步操作。参数如下:
名称 | 类型 | 描述 |
---|---|---|
coll | Array / Iterable / object | 要迭代的集合。 |
limit | number | 一次异步操作的最大数量。 |
iteratee | AsyncFunction | 对于 coll 中的每一个item,迭代执行该异步函数。用(item, callback) 调用,callback 可选。 |
callback | [ function ] | 所有iteratee 函数完成后或发生错误时触发的回调函数。用(err, results) 调用。results 可以是iteratee 函数完成后触发callback 时传递的项。 |
具体实现:
var superagent = require('superagent')
var cheerio = require('cheerio')
var async = require('async')
var url = require('url')
var cnodeUrl = 'https://cnodejs.org/';
superagent.get(cnodeUrl).end(function(err, res) {
if (err) {
return console.error(err)
}
// 存放标题url的数组
var topicUrls = [];
var $ = cheerio.load(res.text);
//获取首页所有的链接
$('#topic_list .topic_title').each(function (idx, el) {
if (idx < 40) {
var $el = $(el);
var href = url.resolve(cnodeUrl, $el.attr('href'));
topicUrls.push(href);
}
});
//并发连接数的计数器
var concurrencyCount = 0;
var fetch = function (url, callback) {
console.time(' 耗时');
concurrencyCount++;
superagent.get(url).end( function (err, res) {
console.log('并发数:', concurrencyCount--, 'fetch', url);
//var $ = cheerio.load(res.text);
callback(null, [url, res.text]);
});
}
async.mapLimit(topicUrls, 11, function (topicUrl, callback) {
fetch(topicUrl, callback);
console.timeEnd(" 耗时");
}, function (err, result) {
result = result.map( function (pair) {
var $ = cheerio.load(pair[1]);
return ({
title: $('.topic_full_title').text().trim(),
href: pair[0],
comment1: $('.reply_content').eq(0).text().trim(),
author1: $('.reply_author').eq(0).text().trim() || "评论不存在",
});
});
console.log('final:\n',result);
});
});
$ node app.js
耗时: 2.108ms
耗时: 0.748ms
耗时: 0.641ms
耗时: 0.596ms
耗时: 1.060ms
耗时: 1.429ms
耗时: 0.728ms
耗时: 0.653ms
耗时: 1.177ms
耗时: 0.820ms
耗时: 3.520ms
并发数: 11 fetch https://cnodejs.org/topic/5a54a8a4afa0a121784a8ab0
耗时: 0.802ms
并发数: 11 fetch https://cnodejs.org/topic/5a61ad4ece45d44045146172
耗时: 0.703ms
并发数: 11 fetch https://cnodejs.org/topic/5a66e5899288dc81532880b0
耗时: 0.694ms
......
并发数: 11 fetch https://cnodejs.org/topic/5a37c17dd92f2f5b185acfc4
耗时: 0.684ms
并发数: 11 fetch https://cnodejs.org/topic/5a62125cce45d44045146198
耗时: 0.674ms
并发数: 11 fetch https://cnodejs.org/topic/5a668f8fafa0a121784a8e9b
耗时: 0.682ms
并发数: 11 fetch https://cnodejs.org/topic/5a61e5d8afa0a121784a8dc4
并发数: 10 fetch https://cnodejs.org/topic/5a65adc39288dc8153288058
并发数: 9 fetch https://cnodejs.org/topic/5a5b7638a3692d014f4f146e
并发数: 8 fetch https://cnodejs.org/topic/59523d04984e31dd458c14a4
并发数: 7 fetch https://cnodejs.org/topic/5a6335bbafa0a121784a8dfe
并发数: 6 fetch https://cnodejs.org/topic/5a55617299d207fa49f5cd85
并发数: 5 fetch https://cnodejs.org/topic/5a659dc5afa0a121784a8e6f
并发数: 4 fetch https://cnodejs.org/topic/5a637604ce45d440451461c5
并发数: 3 fetch https://cnodejs.org/topic/5a5c8d2eafa0a121784a8c05
并发数: 2 fetch https://cnodejs.org/topic/59c0d4038812ce51127a8fe5
并发数: 1 fetch https://cnodejs.org/topic/5a4db120ebc575dc49b27108
final:
[ { title: '置顶\n\n\n\n 玉伯《从前端技术到体验科技(附演讲视频)》',
href: 'https://cnodejs.org/topic/5a54a8a4afa0a121784a8ab0',
comment1: '已经过玉伯本人授权,稍后会同步发到node全栈公众号',
author1: 'i5ting' },
{ title: '置顶\n\n\n\n 企业级 Node.js 框架 Egg 发布 2.0,性能提升 30%,拥抱 Async',
href: 'https://cnodejs.org/topic/5a2403226190c8912ebaceeb',
comment1: '顺便拉下票,OSChina 开源中国正在举办 2017年度最受欢迎中国开源软件评选,请为 Egg 打 Call~\n另
外,顶楼『分享交流』章节的两个 Slide 推荐看下~',
author1: 'atian25' },
{ title: '置顶\n\n\n\n 测试请发到客户端测试专区,违规影响用户的,直接封号',
href: 'https://cnodejs.org/topic/592917b59e32cc84569a7458',
comment1: '其实发到招聘板块,首页是看不到的\nsource vue-cnode mobile 2.0',
author1: '1340641314' },
......
参考
《使用 async 控制并发》
mapLimit(coll, limit, iteratee, callbackopt)
Javascript中的Callback方法浅析