nodejs常用模块async(waterfall,each,eachSeries,whilst)

这篇文章主要介绍nodejs的常用模块async,nodejs是异步io的,回头看看自己写的代码,回调函数几乎无处不在,这时候,管理好你的回调函数,理清你自己的思路就变得无比重要。(如果你还停留在闷头写代码,只是为了实现功能,那建议你放空心态,推倒重来)

先看一段代码

var objs = [{name:'A'}, {name:'B'}, {name:'C'}];

function doSomething(obj, cb)
{
    console.log("我在做" + obj.name + "这件事!");
    cb(null, obj);
}

我们要依次把objs中的3件事做完,顺序为A->B->C,我们可以按下面这样

doSomething(objs[0], function(err, data){
    if(err)
    {
        console.log('处理错误!');
    }
    else
    {
        doSomething(objs[1], function(err, data){
            if(err)
            {
                console.log('处理错误!');
            }
            else
            {
                doSomething(objs[2], function(err, data){
                    if(err)
                    {
                        console.log('处理错误!');
                    }
                    else
                    {
                        console.log('处理成功!');
                    }
                });
            }
        });
    }
});

嗯,层次好多,没错,这就是nodejs的异步IO的必然结果。如果我们从头想一想,回到我们做这些的事的出发点,应该如下面这样

做A这件事
如果A成功,再做B这件事
如果B成功,再做C这件事

安装async模块,命令行下

npm install --save async

就相瀑布一样,飞流直下三千尺,而不是一直往右缩进(tab and tab),看看async给我门的模型

var async = require('async');

async.waterfall([
    function(cb)
    {
        doSomething(objs[0], cb);
    },
    function(data, cb)
    {
        doSomething(objs[1], cb);
    },
    function(data, cb)
    {
        doSomething(objs[2], cb);
    }
], function (err, result) {
    if(err)
    {
        console.log('处理错误!');
    }
    else
    {
        console.log('处理成功!');
    }
});

这就是瀑布模型,先别急,我们来看看到底是发生了,我把代码添加上注释,还有运行结果,就好理解了。

var async = require('async');

async.waterfall([
    //A这件事
    function(cb)
    {
        doSomething(objs[0], function(err, dataA){
            console.log(dataA);
            cb(err, dataA);     //如果发生err, 则瀑布就完了,后续流程都不会执行,B和C都不会执行
        });
    },
    //B这件事,dataA就是上一步cb(err, dataA)中传进来的dataA
    function(dataA, cb)
    {
        doSomething(objs[1], function(err, dataB){
            console.log(dataB);
            cb(err, dataA, dataB);  //如果发生err, 则瀑布就完了,后续流程都不会执行,C不会执行
        });
    },
    //C这件事
    function(dataA, dataB, cb)
    {
        doSomething(objs[2], function(err, dataC){
            console.log(dataC);
            cb(err, dataA, dataB, dataC);
        });
    }
], function (err, dataA, dataB, dataC) {    //瀑布的每一布,只要cb(err, data)的err发生,就会到这
    if(err)
    {
        console.log('处理错误!');
    }
    else
    {
        console.log('处理成功!');
        console.log(dataA);
        console.log(dataB);
        console.log(dataC);
    }
});

console的输出

我在做A这件事!
{ name: 'A' }
我在做B这件事!
{ name: 'B' }
我在做C这件事!
{ name: 'C' }
处理成功!
{ name: 'A' }
{ name: 'B' }
{ name: 'C' }


下一个要介绍的模型,whilst,一直执行主函数,直到条件不满足,或者发生异常

var async = require('async');

var i = 0;
async.whilst(
    //条件
    function() {
        return i < 3;   //true,则第二个函数会继续执行,否则,调出循环
    },
    function(whileCb) { //循环的主体
        console.log(i);
        i++;
        whileCb();
    },
    function(err) {         //here 如果条件不满足,或者发生异常
        console.log("err is:" + err);
        console.log("end,the i is:" + i);
    }
);


i = 0;
async.whilst(
    function() {
        return i < 3;   //true,则第二个函数会继续执行,否则,调出循环
    },
    function(whileCb) { //循环的主体
        console.log(i);
        i++;
        if(i == 2)
        {
            whileCb("It's time to break.");
        }
        else
        {
            whileCb();
        }
    },
    function(err) {         //here 如果条件不满足,或者发生异常
        console.log("err is:" + err);
        console.log("end,the i is:" + i);
    }
);

程序的输出

0
1
2
err is:undefined
end,the i is:3
0
1
err is:It's time to break.
end,the i is:2

这个模型,在有些场合下十分有用,以后说到数据库记录的版本管理的时候会说到。


第三个,each,这个就不多说了,处理记录集是每一个程序员都要遇到的问题。看例子

var async = require('async');

var objs = [{name:'A'}, {name:'B'}, {name:'C'}];

function doSomething(obj, cb)
{
    console.log("我在做" + obj.name + "这件事!");
    cb(null, obj);
}

async.each(objs, function(obj, callback) {
    doSomething(obj, function(){
        callback();
    });
}, function(err){
    console.log("err is:" + err);
});

async.each(objs, function(obj, callback) {
    doSomething(obj, function(){
        callback("It's a err.");
    });
}, function(err){
    console.log("err is:" + err);
});

再看输出

我在做A这件事!
我在做B这件事!
我在做C这件事!
err is:undefined
我在做A这件事!
err is:It's a err.
我在做B这件事!
我在做C这件事!

第一个each相信大家都很好理解,A、B、C都顺利执行。


第二个each,相信90%的nodejs的新手程序员都不明白,因为nodejs是异步,函数必然阻塞。(同一函数同时只有一个所谓的线程执行它),也就是不存在所谓的线程安全问题(这句定义其实本身又存在问题,因为异步会导致必然的上一层共享数据的安全问题,也就是说,nodejs不会有同层次的线程安全问题),得先理解,什么是栈。


第四个,eachSeries,这个和each差不多,简单些,就是遍历每一个对象是分步的,上一个对象的callback执行完之后,在执行下一个。

var async = require('async');

var objs = [{name:'A'}, {name:'B'}, {name:'C'}];

function doSomething(obj, cb)
{
    console.log("我在做" + obj.name + "这件事!");
    cb(null, obj);
}

async.eachSeries(objs, function(obj, callback) {
    doSomething(obj, function(){
        callback();
    });
}, function(err){
    console.log("err is:" + err);
});


//和each是有明显区别的,如果没有异步调用,和each无差别,如果有异步调用,则区别十分大
async.eachSeries(objs, function(obj, callback) {
    doSomething(obj, function(){
        callback("It's a err.");
    });
}, function(err){
    console.log("err is:" + err);
});

输出

我在做A这件事!
我在做B这件事!
我在做C这件事!
err is:undefined
我在做A这件事!
err is:It's a err.

看到第二个eachSeries了吧,第二个A执行了之后,抛出了异常,B,C是必然不会被执行的。


async是我日常工作中用的最多的一个工具模块了。这种帮我们理清程序和思路的工具,用熟悉一个就好。相信大家会走得更远。




  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值