node.js async实践分享

nodejs是基于事件驱动的,所有的一切都是异步调用的,这种实现机制优点确实十分明显,那就是避免了同步调用的无尽等待。一直以来,node.js用着都是比较令人感觉兴奋的,直到有一天,我陷入了它埋藏的无尽的回调深坑中,让我内牛满面。

记得那是一个秋天,大约在冬季,我在我的代码小王国里做一件小事。我都觉得这个事情实在太小了,小的都不好意思说,不过我还是要说,我要在redis缓存中找jiangcs520这个哥们养的一条狗狗,事情是这样的,redis里面存了张用户表,记录了用户有哪些朋友,还存了一张人-狗表(没有骂人的意思哦),其实是记录了每一用户养了那条狗,还有一张狗狗表,记录了狗狗的nickname,再给大家整理一下,总共三张表:user表,user_Dog表,dog表。那我为什么要找这样一条狗狗呢,事情是这样的,春天来了,狗狗的春天也来了,然后有个朋友(男)对博主(男)说,大家朋友多年,情同手足,虽然我们性别不和,不过我们两家狗狗的性别合适,要不结个亲,这事就说定了,狗狗成亲那天,那条美女狗狗来了,博主的狗狗还在redis中存着呢,肯定要先喊出来啦,以前,用java的时候,好方便啊,一下就找出来了,先从user表中找到博主jiangcs520,然后从user_Dog表中找到他养的帅狗狗名字,然后在dog表中找到那条狗狗,牵出来就好咯。但是在node.js中就不是这样啦,虽然是同样的顺序,但是大家都懂的,是异步啦,结果都是在回调函数中返回,伪代码如下:

dbDAO.select(usersql,function(err,users){ //第一层查询用户表
    if(err){
        logger.error(err);
    }else{
        if(users){
            dbDAO.select(user_dogSql,function(err,user_dogs){//第二层查询用户-狗狗表
                if(user_dogs){
                    dbDAO.select((dogSql,function(err,dogs){//第三层查询狗狗表
                        if(dogs){
                            "找到狗狗了,牵出来啦"
                        }
                    }))
                }
            })
        }
    }
});

node.js中,就需要如上三层的回调,如此简单的一个查询,就需要三层回调,那要是我还要查询狗狗的亲戚,狗狗生出的狗仔的另一半的亲戚,那怎么办,得套几层啊,几百行代码全是回调的,谁不晕倒,node还有人用吗。就在这个危难关头,回调世界救世主出现了,它就是“async”,粉墨登场。

如上的问题,async是如何解决的呢,看看救世主是如何拯救回调大军的,伪码如下:

async.waterfall([
    function(cb){
        //查询用户表
        dbDAO.select(usersql,function(err,users){
            cb(err,results);
        });
        
    },function(results,cb){
        //查询用户_狗狗表
        dbDAO.select(user_dogSql,function(err,users){
            cb(err,results);
        });
    },function(results,cb){
        //查询狗狗表
        dbDAO.select(dogSql,function(err,users){
            cb(err,results);
        });
    }
],function(err,results){
    //查到狗狗了,可以牵出来了
})


是不是觉得看着更有层次感,更加清晰。这里是使用了async的瀑布流waterfull方法,第一个参数就是需要执行的方法数组,第二个参数就是一个回调函数,观察一下这个函数数组,每一个函数结构都是类似的,首先看第一个函数,有一个参数cb,其实这个参数是async自己内部指定的,当我们在函数体内处理完了我们需要处理的事情,就需要调用这个函数,如上方式cb(err,results),再来看第二个函数,与第一个函数有所区别,有两个参数,results和cb,其实这个results是上一函数处理完的结果传递下来的,是不是很像瀑布一样,所以才命名为瀑布流的吧。第三个函数就不讲了,同样道理。这里要注意cb回调函数很重要,若cb忘了执行或者是某个cb回调未执行,那么,这个瀑布流就无法继续下去了,waterfull中的回调函数也不会执行。还有一种情况,若其中某个函数中出现了错误,接下来的函数不会继续执行,在调用了当前的cb回调函数后,会直接进入waterfull的回调函数中。比如我们在查询用户_狗狗表的时候,处理完后忘了调用回调函数cb,那么,故事就到此结束了,不会继续往下走了,若我们都没忘记这一茬,但是数据查询的时候出错了,那么接下来的查询狗狗表也就没有了,但是与前一种情况的区别是会进入waterfull的回调函数,错误信息err就作为参数传递了。

async还有几个常用的方法:series,parallel,auto方法等等。在业务逻辑较为复杂的情况下,这些方法都是十分好用的。series顾名思义比较好理解,顺序执行,按照函数数组的顺序执行所有方法,parallel是平行的意思,就是同时执行的意思,那么具体哪个函数先返回就不好说了,但是回调函数中返回的结果是按照函数数组的顺序返回的。更加具体详细的使用方法再给大家推荐一篇博文:http://www.verydemo.com/demo_c441_i206465.html

最后提醒一个容易粗错的地方,当大家检查完代码都没有问题,但是最终回调函数始终没有执行的时候,可以检查一下,函数数组中的所有函数执行完后是否都已经调用cb,若少了任意一个,都是无法执行到最后的。

对已async的实践还不多,吐槽拍砖请随意。



猜你喜欢

转载自blog.csdn.net/jiangcs520/article/details/17350927