• Nodejs异步框架——async


    上次的网页爬虫写完后,又打算做一个爬图的工具。前两天已经写好了代码。思路如下:

    分析页面还是采用cheerio,对<div>中的img进行分析抽取,拿到图片的url。然后用childprocess调用系统的curl工具来下载这些远程url的图片。最后将这些写入到系统的硬盘中。

    功能代码如下(只是下载图片的功能代码):

    var url=require('url');
    var fs=require('fs');
    var cp=require('child_process');
    
    var DOWNLOAD_DIR='./';
    var file_url='http://htmljs.b0.upaiyun.com/uploads/1396874069658-nodejs_1280x1024.png';
    
    function downloads(file_url){
            var filename=url.parse(file_url).pathname.split('/').pop();
            var file=fs.createWriteStream(DOWNLOAD_DIR+filename);
            var curl=cp.spawn('curl',[file_url]);   //use spawn
            curl.stdout.on('data',function(data){
                    file.write(data);
            });
            curl.stdout.on('end',function(data){
                    file.end();
            console.log(filename+'downloaded to'+DOWNLOAD_DIR);
            });
    
            curl.on('exit',function(code){
                    if(code!=0){
                            console.log('Failed:'+code);
                    }
            });
    
    };
    
    downloads(file_url);

    但是发现了一个问题。就是下载的图的数量比较少的时候,一切都还好。当循环页面下载的时候,一旦并行任务过多,立刻就不行了。因为并发量太大。

    后来尝试用http的get方法来读图片,结果性能更不行,还不如系统的curl。

    去cnode请教了一下,有前辈说需要限制一下并发量,用aysnc。

    也是在下班后等零碎的时间,去aysnc的github(https://github.com/caolan/async)上看了一下,运行了几个实例。发现async的确不错。

    先说下js异步回调的问题,按照传统的回调来,处理回调中的数据,发现只能一层套一层的。刚开始感觉这种方式不错,后来套的多了,才发现这种方式,太死了。

    async是解决这个问题的。

    为了解决我遇到的问题,所以着重看了一下它的控制流方面的东西。

    async.series 和parallel.

    这两个,一个是顺序的一个是并行的。

    api里面有讲他的用法,他们都有(tasks, [callback])的参数。第一个参数是任务,第二个是得到前面任务数据的callback。

    其中多个task,可以用数组,也可以用对象。本人倾向用对象。

    async.series({
        one: function(callback){
            callback(null, 'one');
        },
        two: function(callback){
            callback(null, 'two');
        }
    },
    function(err, results) {
        // results is now equal to: {one: 'one', two: 'two'}
    });

    同样,可以打印results中的某些属性,results.one什么的。

    parallel和series是一样的用法。

    所以,采用这种并行的方式,把之前写的工具改造一下,我们就不需要再往下套函数处理了:

    var cheerio=require('cheerio');
    var request=require('request');
    var fs=require('fs');
    var async=require('async');
    
    var url='http://www.cnblogs.com/juepei/';
    var result=new Array();
    
    async.parallel({
            one:function(cb){
                    request(url,function(error,res,body){
                            if(!error && res.statusCode==200){
                                    var $=cheerio.load(body);
                                    $('div').filter(function(i,ele){
                                            if($(this).attr('class')==='postTitle'){
                                                    result.push($(this).text().trim());
                                            }
                                    });
                                    //console.log(result);
                                    cb(result);
                            }
                    });
            }
    },function(err,results){
            if(err){
                    console.log(err);
            }else{
                    console.log(results.one);
            }
    });

    关于最后一个回调函数,必须要处理err,不然的话,会报results为undefined。这是不是async规定的,目前还不知道,如果有前辈知道为何,请赐教。

    从而,再下载大量图片的时候,我们就可以采用parallelLimit(tasks, limit, [callback])这个函数,对并行任务的数量进行限制一下,就可解决问题了。晚上回去试试,看是不是已经ok了。

    在此附上本人的github地址:https://github.com/ThinkCats ,大家可以相互交流,共同进步。

  • 相关阅读:
    util-tool工具 、时间格式化
    好用的 UI 调试技巧
    扩展jQuery的方法
    mybatis判断是否传递了条件
    mysql创建视图不允许子查询
    springMVC传递MAP给JS
    XPS15 安装ubuntu之后无法进入系统
    XPS15 9560 切换显卡之后,无法登陆的解决方式
    fedora安装chrome报错
    linux挂载硬盘
  • 原文地址:https://www.cnblogs.com/juepei/p/4228043.html
Copyright © 2020-2023  润新知