• js的同步异步


    由于js没有多线程,所以处理多任务的时候,可以用异步回调来解决。js中setTimeout、setInterval、ajax(jq中可以选择同步或异步)均会开启异步。遇到异步模块,会将其推入值任务队列中,继续向下执行
    最后等待异步模块处理完成后,cpu会自动接收到通知,然后从任务队列中取出执行。



    先来看个需求
    我有一个页面,和两个接口,一个是获取所有老师,一个是根据老师id获得该老师所管理的学生。要求是在该页面都展示出来。

    后端代码

    // 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
    const Koa = require('koa2');
    const Router = require('koa-router');
    // 创建一个Koa对象表示web app本身:
    const app = new Koa();
    const router=new Router();
    const bodyParser = require('koa-bodyparser')//解析请求参数中间件
    app.use(bodyParser())
    
    
    // cors跨域
    app.use(async (ctx, next) => {
        console.log(`Process ${ctx.request.method} ${ctx.request.url}...`);
        ctx.set("Access-Control-Allow-Origin", "*");
        ctx.set("Access-Control-Allow-Headers", "x-requested-with, accept, origin, content-type");
        ctx.set("Content-Type", "application/json,application/x-www-form-urlencoded,text/plain");
        await next();
    });
    
    
    //获取所有老师
    router.post('/getTeacher', async ( ctx ) => {
        let st=[
          {id:20170101,name:'张老师',age:48},
          {id:20170102,name:'王老师',age:36},
          {id:20170103,name:'丁老师',age:52}
        ];
        ctx.response.type = 'application/json';
        ctx.body ={
          total:st.length,
          rows:st
        }
    })
    
    //获取老师名下的学生
    router.post('/getTs', async ( ctx ) => {
        let reqParam= ctx.request.body;
        let tid=reqParam.tid;//teacher的id,是个数组
        let data={
            20170101:{
              tname:'张老师',
              students: [
                {id:20170201,name:'小明',age:12},
                {id:20170202,name:'小红',age:10}
              ]
            },
           
            20170102:{
              tname:'王老师',
              students: [
                {id:20170203,name:'小白',age:11}
              ]
            },
    
            20170103:{
              tname:'丁老师',
              students: [
                {id:20170204,name:'小青',age:8},
                {id:20170205,name:'小紫',age:10}
              ]
            }
        };
          
        let matching={};
        let unMatching=[];
        tid.forEach(function(item){
          if(data[item]==undefined){
            unMatching.push(item)
          }else{
            matching[item]=data[item]
          }
          
        })
        
        let rep={
          unMatching:unMatching,//匹配到的
          matching:matching//未匹配到的
        }
        
        
        ctx.response.type = 'application/json';
        ctx.body =rep;
    })
    
    
    
    
    // 加载路由中间件
    //解释:app.use 加载用于处理http請求的middleware(中间件),当一个请求来的时候,会依次被这些 middlewares处理。
    app.use(router.routes());
    
    // 在端口3000监听:
    app.listen(1234, () => {
      console.log('[myapp]已经运行,端口为1234')
    })
    View Code
    {
      "name": "test",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo "Error: no test specified" && exit 1"
      },
      "author": "",
      "license": "ISC",
      "dependencies": {
        "koa2": "^2.0.0-alpha.7",
        "koa-router": "^7.3.0",
        "koa-bodyparser": "^4.2.0"
      }
    }
    View Code

    接口返回数据如下
    请求方式:post,参数:无

    请求方式:post,参数:tid:[20170101,20170102,20170102]

    效果图如下

    准备工作
    先把页面基础布局写好,因为我不想拼接字符串,所以用了腾讯的字符串模板引擎artTemplate

    index.html

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Title</title>
            <style>
                table{border-collapse:collapse ;}
                td,th{border: red solid 1px; width: 80px; text-align: left;}
            </style>
        </head>
        <body>
            <script id="tsTp" type="text/html">
                <h1>老师所照顾的学生‘对应表’</h1>
                {{each ts v k}}
                    <fieldset> 
                        <legend>{{v.tname}}</legend>
                         <table >
                            <thead>
                                <tr>
                                    <th>姓名</th>
                                    <th>年龄</th>
                                </tr>
                            </thead>
                            <tbody>
                                {{each v.students st}}
                                <tr>
                                    <td>{{st.name}}</td>
                                    <td>{{st.age}}</td>
                                </tr>
                                {{/each}}
                            </tbody>
                        </table>
                   </fieldset>
                {{/each}}
            </script>
            <button>测试</button>
            <script src="lib/jquery-3.2.1.min.js"></script>
            <script src="lib/template-web.js"></script>
            <script src="js/index.js"></script>
        </body>
    </html> 

    Es5解决(嵌套式回调

    var service={
        //获取老师
        getTeacher:function(calBack){
            $.post('http://47.93.52.112:1234/getTeacher',function(rep){
                calBack(rep)
            })
        },
        //获取老师对应下的学生(Ts:某个老师的学生)
        getTs:function(param,calBack){
            $.post('http://47.93.52.112:1234/getTs',param,function(rep){
                calBack(rep)
            })
        }
    }
    
    $('button').click(function(){
        service.getTeacher(function(rep){
            let teachers=rep.rows;
            let tid=[];
            teachers.forEach(function(item){tid.push(item.id)})
            
            service.getTs({tid:tid},function(rep){
                let ts=rep.matching;
                
                //渲染至页面
                let tsTpData={ts:ts};
                $('body').html(template('tsTp', tsTpData));
            })
        })
    })
    View Code

     

    Es6解决(promise,链式回调
    这样可以避免回调函数的地狱

    var service={
        //获取老师
        getTeacher:function(){
            return new Promise(function(resolve, rejec){
                $.post('http://47.93.52.112:1234/getTeacher',function(rep){
                    resolve(rep)
                })
            })
        },
        //获取老师对应下的学生(Ts:某个老师的学生)
        getTs:function(param){
            return new Promise(function(resolve, rejec){
                $.post('http://47.93.52.112:1234/getTs',param,function(rep){
                    resolve(rep)
                })
            })
        }
    }
    
    $('button').click(function(){
        service.getTeacher().then(function(rep){
            let teachers=rep.rows;
            let tid=[];
            teachers.forEach(function(item){tid.push(item.id)})
            
            service.getTs({tid:tid}).then(function(rep){
                let ts=rep.matching;
                
                //渲染至页面
                let tsTpData={ts:ts};
                $('body').html(template('tsTp', tsTpData));
            })
        })
    })
    View Code

    注释:
    新版的jq的ajax,本身已经实现了promise的链式回调,故我们可以直接使用,我这里只是演示

    Es7解决(异步的终极解决方案-Async/Await
    目标就像同步调用那么爽,感觉不出来是回调

    • 可以让异步逻辑用同步写法实现
    • 最底层的await返回需要是Promise对象
    • 可以通过多层 async function 的同步写法代替传统的callback嵌套
    var service={
        //获取老师
        getTeacher:async function(){
            let result=await $.post('http://47.93.52.112:1234/getTeacher');
            return result;
        },
        //获取老师对应下的学生(Ts:某个老师的学生)
        getTs:async function(param){
            let result=await $.post('http://47.93.52.112:1234/getTs',param);
            return result;
        }
    }
    
    $('button').click(async function(){
        let teachers=(await service.getTeacher()).rows;
        let tid=[];
        teachers.forEach(function(item){tid.push(item.id)});
        let ts=(await service.getTs({tid:tid})).matching;
        //渲染至页面
        let tsTpData={ts:ts};
        $('body').html(template('tsTp', tsTpData));
    })
    View Code

    一个完整的前后端demo
    前端:jq、后端:node
    前端

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            table{border-collapse: collapse;}
            td,th{
                border: red solid 1px;
                padding:4px 20px ;
            }
        </style>
    </head>
    <body>
        <table>
            <thead>
                <tr>
                    <th>姓名</th>
                    <th>性别</th>
                    <th>邮寄地址</th>
                </tr>
            </thead>
            <tbody class="tbd"></tbody>
        </table>
        <div class="ybs"></div>
        <script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
        <script>
            //service
            let service={
                getStudents() {
                    return $.get('http://www.dshvv.com:3000/getStudents');
                },
                getStuDetail(param){
                    return $.post('http://www.dshvv.com:3000/getStuDetail',param);
                },
                getYb(param){
                    return $.post('http://www.dshvv.com:3000/getYb',param);
                }
            }
    
    
            //初始化执行
            let inits = async ()=>{
                //获取所有的学生列表
                let students=await service.getStudents();
                let tbodyDom='';
                students.forEach(function (item) {
                    tbodyDom+=`<tr>
                       <td>${item.name}</td>
                       <td>${item.sex}</td>
                       <td class="ybTouch" data-sid="${item._id}">点击查看邮编</td>
                    </tr>`;
                })
                $('.tbd').html(tbodyDom)
            }
            inits()
    
    
            //事件
            $(document).on('click', '.ybTouch', async function() {
                //获取学生详情
                let stuDetail=await service.getStuDetail({sid:$(this).data('sid')});
                let ybResult=await service.getYb({adds:stuDetail.province});
                $('.ybs').html(`查询到此人家的邮编是:${ybResult.result}`)
            });
        </script>
    </body>
    </html>


    后端

    module.exports=function (route) {
        route
            .get('/getStudents',async ctx=>{
                ctx.response.type = 'text/json';
                ctx.response.body=[{
                    "_id" : "5b4da81c3b28c3253a3c168a",
                    "sex" : "女",
                    "name" : "王丽云"
                },{
                    "_id" : "5b4da81c3b28c3253a3c168b",
                    "sex" : "男",
                    "name" : "丁少"
                }, {
                    "_id" : "5b4da81c3b28c3253a3c168c",
                    "sex" : "男",
                    "name" : "张中秋"
                }]
            })
    
            .post('/getStuDetail',async ctx=>{
                ctx.response.type = 'text/json';
                let param=ctx.request.body;
                console.log(param)
                let sid=param.sid;
                let sdt={
                    "5b4da81c3b28c3253a3c168a":{
                        "_id" : "5b4da81c3b28c3253a3c168a",
                        "province" : "郑州市",
                        "sex" : "女",
                        "name" : "王丽云",
                        "birth" :"20180101"
                    },
                    "5b4da81c3b28c3253a3c168b":{
                    "province" : "广州市",
                    "sex" : "男",
                    "name" : "丁少",
                    "birth" :"20180102"
                    },
                    "5b4da81c3b28c3253a3c168c":{
                        "province" : "北京市",
                        "sex" : "男",
                        "name" : "张中秋",
                        "birth" :"20180102"
                    }
                }
                ctx.response.body=sdt[sid]
            })
            .post('/getYb',async ctx=>{
                ctx.response.type = 'text/json';
                let param=ctx.request.body;
                let adds=param.adds;
                let ybs={
                    "郑州市":450000,
                    "广州市":510000,
                    "北京市":100000
    
                }
                let res='';
                for(let itm in ybs){
                    if(itm==adds){
                        res=ybs[itm]
                    }
                }
                ctx.response.body={
                    result:res
                }
            })
    
    }
    


    效果

      

    参考:
    在 Node.js 的开发中,由于逻辑分层所致,会出现多层回调。易于引发异常处理混乱、闭包过于复杂、代码难以维护等问题。于是就引发了异步编程优雅解决的各大方案
    http://cnodejs.org/topic/5640b80d3a6aa72c5e0030b6
    http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html

  • 相关阅读:
    Oracle instr() 字符查找函数
    Oracle 中触发器增加存储过程commit问题
    Oracle 记录下jdbc thin client module名称
    sqoop job 实现自动增量导入
    Linux LVM--三种Logic Volume
    Kafka ISR and AR HW 、 LEO
    Kafka Rebalance机制分析
    Kafka 基础操作
    Kafka 通过python简单的生产消费实现
    Kafka为什么速度那么快?该怎么回答
  • 原文地址:https://www.cnblogs.com/dshvv/p/7691227.html
Copyright © 2020-2023  润新知