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 ,大家可以相互交流,共同進步。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM