• 在NodeJS中使用流程控制工具Async


    本文介绍一款流程控制工具async,在编写接口或者编写测试用例的过程中总是会用到它。

    由于nodejs是异步编程模型,有一些在同步编程中很容易做到的事情,现在却变得很麻烦。Async的流程控制就是为了简化这些操作。

    在node.js的开发和学习过程中,开始我们的目的只有一个就是实现功能,并不注重代码质量和可读性,也没有这个意识。像我之前在接口的实现过程中滥用中间件,以为结果出来了,把它response.send(result)出去就万事大吉了。

    后来参考别人的代码,真心感到惭愧,然后才一步步学会注重代码的可读性。对比一下,之前的代码:

    //根据course_id查询一条课程信息,及章节列表
    router.get('/getOne',courseController.findOne,chapterController.findByCourseID,function(req,res){
        var result=util.response.getInfoOK;
        result.item = req.course;
        result.courseitemList = req.courseitemList;
        req.course = null;
        req.courseitemList = null;
        res.send(result);
    });


    这种写法看起来非常简洁,它的思路是这样的,在这个接口中,我需要调用多个controller中的方法,request、response会跟随请求依次流向这个方法,通过request把参数带过去,通过response把请求结果带过来。


    现在的代码:

    //申请详情
    router.get('/myServiceHandleInfo', function (req, res, next) {
    
        async.auto({
            rs:function(cb){  //user-server关系
                serviceCtrl.getHandleRS(req.query, function (err, result) {
                    cb(err,JSON.parse(result));
                });
            },
            service:function(cb){  //服务详情
                console.log("sid:",req.query.sid);
                serviceCtrl.getInfo({sid:req.query.sid}, function (err, result) {
                    console.log("service result:",result);
                    cb(err,JSON.parse(result));
                });
            },
            app:function(cb){  //应用详情
                appCtrl.showAppDetail(req.query.appid, function (err, result) {
                    cb(err,JSON.parse(result));
                });
            },
            appUser:['app', function(results,cb) {  //应用创建者详情
                userCtrl.getInfo({uid:results.app.obj.did},function(err,result){
                    cb(err,JSON.parse(result));
                })
            }]
        },function(err,results){
            if (err) throw err;
            res.send(results);
        });
    });


     使用async之后,代码结构性和可读性都得到了改善,相信你一旦使用后,就再也不能没有它了。


    对比:

    1. response中参数的名称不能重复,而且response的负担特别重。async只在入口处将参数给这个方法,async请求结果是通过回调函数带过来的。

    2. 方法之间是一个执行完了,才会执行下一个。而async有同步、异步、自动等多种方式。
     

    ================ ===========  开始使用Async   ====== ========================


    Async的内容分为三部分:

        流程控制:简化常见流程的处理
        集合处理:如何使用异步操作处理集合中的数据
        工具类:几个常用的工具类

     
    安装工具

    npm install async --save -d


    1.async.waterfall实例(多个函数依次执行,且前一个的输出为后一个的输入)

    这个函数名为waterfall(瀑布),可以想像瀑布从上到下,按顺序依次执行多个函数。不同之处,每一个函数产生的值,都将传给下一个函数。如果中途出错,后面的函数将不会被执行。错误信息以及之前产生的结果,将传给waterfall最终的callback。
    注意,该函数不支持json格式的tasks。
    应用场景:在创建课程的接口中,首先解析表单和上传头像,然后保存课程到数据库

    async.waterfall([
        function(cb) {
         util.formParse(req,function(err,result){  //from解析
                  cb(err,result);
              });  
        },
        function(user, cb) {
            courseCtrl.create(course,function(err,result){ //保存到数据库
                cb(err,result);
            })
        }
    ], function (err, result) {
        if(err) throw  err;
        var results = util.response.regOK;
        results.item = result;
        res.send(results);
    });

     
    2.async.parallel 实例(多个函数并行执行)

    并行执行多个函数,每个函数都是立即执行,不需要等待其它函数先执行。传给最终callback的数组中的数据按照tasks中声明的顺序,而不是执行完成的顺序。
    如果某个函数出错,则立刻将err和已经执行完的函数的结果值传给parallel最终的callback。其它未执行完的函数的值不会传到最终数据,但要占个位置。
    支持json形式的tasks,其最终callback的结果也为json形式。
    应用场景:在获取课程列表接口中,要获取课程列表,同时获取课程数目

    async.parallel({
         count:function(cb){
             courseController.count( req.query ,cb);   //课程数目
         },
         list:function(cb){
             courseController.getList( req.query ,cb);   //课程列表
         }
     },function(err,results){
        res.send(results);
     });

     
    请求结果:

    {
    count:2,
    list:[
             {
                courseid:xxx,
                name:xxx
             },
             {
                courseid:xxx,
                name:xxx
             }
         ]
    }


    3.async.auto实例(多个函数有依赖关系,有的并行执行,有的依次执行)

    用来处理有依赖关系的多个任务的执行。比如某些任务之间彼此独立,可以并行执行;但某些任务依赖于其它某些任务,只能等那些任务完成后才能执行。虽然我们可以使用async.parallel和async.series结合起来实现该功能,但如果任务之间关系复杂,则代码会相当复杂,以后如果想添加一个新任务,也会很麻烦。这时使用async.auto,则会事半功倍。
    如果有任务中途出错,则会把该错误传给最终callback,所有任务(包括已经执行完的)产生的数据将被忽略。
    应用场景:

    根据uid(用户id)和course_id(课程id)获取用户信息和用户收藏的视频:
    根据uid,在user表中获取用户信息;
    根据course_id,在course表中获取课程信息,含teacher_id;
    根据teacher_id,在user表中获取讲师信息(上一步执行完,才能执行);
    最后,返回userInfo,courseInfo,tearcherInfo;

    async.auto({
        userInfo:function(cb){
                userCtrl.getInfo({uid:req.query.uid}, function (err, result) {   //用户信息
                cb(err,result);
            });
        },
        couseInfo:function(cb){
            courseCtrl.getInfo(req.query.courseid, function (err, result) {  //课程信息
                cb(err,result);
            });
        },
        tearcherInfo:['couseInfo', function(results,cb) {
            userCtrl.getInfo({uid:results.couseInfo.teacherid},function(err,result){  //讲师信息
                cb(err,result);
            });
        }]
    },function(err,results){
        if (err) throw err;
        res.send(results);
    });

     
    请求结果:

    {
    userInfo:{
        uid:xxx,
        name:xxx
        },
    courseInfo:{
        courseid:xxx,
        name:xxx
        },
    tearcherInfo:{
        uid:xxx,
        name:xxx
        }
    }


    GitHub代码参考地址:https://github.com/wuwanyu/async.node.test

  • 相关阅读:
    Linux磁盘分区实例演示
    浅谈Linux下的rpm
    You have 1 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): shopadmin. Run 'python manage.py migrate' to apply them.
    Xshell Linux常用命令
    OSError: mysql_config not found
    AttributeError: module 'datetime' has no attribute 'now'
    CentOS查看进程端口号以及kill操作
    nginx报错 nginx: [alert] kill(25903, 1) failed (3: No such process)
    3D 散点图的绘制
    关系数据库和非关系型数据
  • 原文地址:https://www.cnblogs.com/wuwanyu/p/wuwanyu20160407.html
Copyright © 2020-2023  润新知