js爬虫和并发控制

模拟假线程池,控制并发数量。


var cheerio = require('cheerio');
var superagent = require('superagent');
var url = require('url');

/**
 * @params list {Array} - 要迭代的数组
 * @params limit {Number} - 并发数量控制数
 * @params asyncHandle {Function} - 对`list`的每一个项的处理函数,参数为当前处理项,必须 return 一个Promise来确定是否继续进行迭代
 * @return {Promise} - 返回一个 Promise 值来确认所有数据是否迭代完成
 */
let mapLimit = (list, limit, asyncHandle) => {
    //定义一个递归函数,相当于从list队列中取任务
    function recursion(taskQueue, threadId) {
        return asyncHandle(taskQueue.shift(), threadId) //每次取队首任务,并从队列里去掉
            .then(() => {//上一个任务resolve后,继续取下一个任务
                if (taskQueue.length !== 0) //任务队列非空,递归继续进行迭代
                    return recursion(taskQueue, threadId);
                else
                    return 'finish';//任务队列清空,返回
            })
    };

    let tempList = [].concat(list);//保存一份副本,避免原本被更改
    limit = (limit < tempList.length) ? limit : tempList.length;//若异步池大小比任务数还大,则缩小异步池
    let asyncPool = []; // 正在进行的所有并发异步操作(异步池)
    let threadId = 0;
    while (limit--) {//往异步池里添加limit个任务,相当于limit个“线程”同时在跑,之后每条任务线再递归地从队列里取下一个任务,和线程池不太一样。
        asyncPool.push(recursion(tempList, threadId++));
    }
    return Promise.all(asyncPool);  // limite个并发异步操作都完成后,返回。
}


let urlList = [];
let cnt = 10;
let domain = 'https://cnodejs.org/';
for (let i = 1; i <= cnt; i++) {
    urlList.push(domain + '?tab=all&page=' + i);
}
//异步处理函数
function crwalFunc(url, threadId) {
    console.log('In thread ' + threadId + '>>>, fetch ' + url + ' begin');
    return new Promise((resolve, reject) => {
        superagent.get(url).end(
            function (err, res) {
                console.log('In thread ' + threadId + '###, fetch ' + url + ' successful');
                //topics.push([url, res.text]);
                resolve();
            }
        );
    });
}
mapLimit(urlList, 5, crwalFunc).then(() => {
    console.log('Done!');
});

执行效果如下

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值