JavaScript之异步

作者: js_hcl | 来源:发表于2019-04-15 15:15 被阅读16次

    一、事件循环

    二、AJAX:定义总结

    //定义request对象
    var request;
    if (window.XMLHttpRequest) {
        request = new XMLHttpRequest();
    } else {
        request = new ActiveXObject('Microsoft.XMLHTTP');
    }
    
    // 发送请求:
    request.open('GET', '/api/categories');
    request.send();
    
    //监听返回状态
    request.onreadystatechange = function () { // 状态发生变化时,函数被回调
        if (request.readyState === 4) { // 成功完成
            // 判断响应结果:
            if (request.status === 200) {
                // 成功,通过responseText拿到响应的文本:
                return success(request.responseText);
            } else {
                // 失败,根据响应码判断失败原因:
                return fail(request.status);
            }
        } else {
            // HTTP请求还在继续...
        }
    }
    
    技巧:异步之后再执行某个函数,则要采用回调函数
    缺点:
    1.不好维护
    2.会形成回调陷阱
    

    三、Promise:定义串行并行总结

    1.定义
    var promise1 = new Promise(function(resolve, reject) {
      //内容略
      if(res.statusCode === 200){
          resolve(res);//即把AJAX的回调放到外面执行,避免回调陷阱及维护问题
      }else{
         reject(res);//resolve,reject,all,race是Promise的静态方法
      }
    });
    //对应两种状态,接受及拒绝
    promise1.then(res=>{//   resolve(res);则这边形参可以接收到这个实参
      console.log(value);
    });
    promise1.catch(res=> {
      console.log(value);
    });
    
    
    2.Promise串行
    eg:promise1.then().catch().finally().then().then()
    
    
    3.Promise并行
    //注意,并行情况下,[]内不能是状态改变的Promise,应该是请求的,而不是then之后的
    all:全都
    Promise.all([promise1,promise2,promise3]).then((res)=>{。。。})
    成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值
    成功时返回的结果数组和原属性数组一致
    场景:执行某个,需要其它的都请求回来了数据
    
    race:赛跑
    Promise.race([promise1,promise2,promise3]).then((res)=>{。。。})
    场景:多个请求,取最新返回的数据
    
    4.总结
    Promise对比AJAX相当于在其外面套了个框架
    优点:形式上解决了AJAX的缺点问题
    

    四、generator生成器函数:定义模拟代码(闭包、field*、next、传参、return)应用场景

    Es6语法
    英 ['dʒenəreɪtə][](javascript:;)* 美 ['dʒɛnəretɚ][](javascript:;)n. 发电机;发生器;生产者

    1.相关技术:闭包

    闭包:函数的内部函数在函数的外部执行,导致该函数不能释放(内部使用到了的变量)
    闭包优势:
    1.状态保存在局部的外部函数内,达到私有属性及保存状态的作用
    缺点:
    1.内存消耗很大
    
    闭包eg:
    function A(){
      function B(){};
      return B;
    }
    let t=A()();//函数的内部函数在函数的外部执行
    

    2.模拟其原理:实现普通、迭代器委托field*、传参、return

    function* Fun2(){
        let x0=yield 'Fun2:0;';
        let x1=yield 'Fun2:1;'+x0;
    }
    function* Fun1() {
        let a=1;
        let y0=yield 'Fun1:0;'+a;
        let y1=yield* Fun2();
        // return 'this is return'
        let y2=yield 'Fun1:2;'+a;
        let y3=yield 'Fun1:3;'+y2;
        let y4=yield 'Fun1:4;'+y2;
        return 'this is return'
    }               
    var x=Fun1();//返回迭代器
    console.log(x.next());//测试加变量。{value: "Fun1:0;1", done: false}
    console.log(x.next());//测试field*。{value: "Fun2:0;", done: false}
    // console.log(x.return('test return'));//测试return。
    console.log(x.next('paraToChild'));//测试给内部迭代器传参。{value: "Fun2:1;paraToChild", done: false}
    console.log(x.next());//测试加变量。{value: "Fun1:2;1", done: false}
    console.log(x.next('para'));//测试自身迭代器传参。{value: "Fun1:3;para", done: false}
    console.log(x.next());//测试保存规律。{value: "Fun1:4;para", done: false}
    console.log(x.next());//测试迭代完。{value: "this is return", done: true}
    console.log(x.next());//测试迭代完。{value: undefined, done: true}
    ----------------------------------------------------------------
    模拟代码:
    需求分析:
    generator生成器:
    1.利用闭包原理//需要定义next为内部函数
    2.每一个yield相当于内部函数,即有多个内部函数
    
    3.子项可能也是迭代器,要遍历进去 field*。如果内部迭代器迭代完,换成迭代自身的
    4.next传参。是设置上一个yield的返回值。因为每个yield转为内部函数,所以下一个field执行,其实之前field返回值并没有保存
    5.return 的实现
    ----------------------------------------------------------------
    function Fun4(){
      // 第一部分:每个yield/return转化为内部函数
        let x0=()=>{return 'Fun4:0;'};
        let x1=()=>{return 'Fun4:1;'+yieldValue[0]};
    
        // 第二部分:状态机
        let index=0;//next状态
        let done=false;//是否迭代完状态,return可以直接终结迭代器
        let yieldValue=[];//传参数组
        let returnObj={0:x0,1:x1,length:2};//迭代器对象
    
        // 第三部分:next,return方法(这边写到外面,不至于阅读混乱)
    
        // 第四部分:返回迭代器
        return returnObj;
    }
    function Fun3(){
        // 第一部分:每个yield/return转化为内部函数
        let a=1;
        let y0=()=>{return 'Fun3:0;'+a};
        let y1=Fun2();//
        // return 'this is return'
        let y2=()=>{return 'Fun3:2;'+a};
        let y3=()=>{return 'Fun3:3;'+yieldValue[2]};
        let y4=()=>{return 'Fun3:4;'+yieldValue[2]};
        let y5=()=>{done=true;return 'this is return';}//return 会置done为true
    
        // 第二部分:状态机
        let index=0;//next状态
        let done=false;//是否迭代完状态,return可以直接终结迭代器
        let yieldValue=[];//传参数组
        let returnObj={0:y0,1:y1,2:y2,3:y3,4:y4,5:y5,length:6};//迭代器对象
    
        //第三部分:next,return方法(这边写到外面,不至于阅读混乱)
    
        // 第四部分:返回迭代器
        return returnObj;
    }
    ----------------------------------------------------------------
    next和return的实现:
    //next方法
    returnObj.next=(arguments)=>{
        if(index>(returnObj.length-1) || done) {//超出或done置为true了,则迭代器终结
            return {value: undefined, done: true}
        }
        switch((typeof returnObj[index])){
            case 'object':{// 如果其是对象,则遍历进去
                let result=returnObj[index].next(arguments);//next传参到内部迭代器
                if(result.done){//说明内部已经执行完了,且超出(改为迭代自身)
                    index+=1;//会自动执行daefault即,迭代自身
                }else{
                    return result;break;
                } 
            }
            default:{//否则迭代自身
                if(arguments && index>0){
                    yieldValue[index-1]=arguments;//next传值,保存到上一个field的返回值
                }
                let result=returnObj[index]();
                index+=1;
                return {value: result, done: false}
            }
        }
    }
    //return方法
    returnObj.return=(arguments)=>{//return方法,可以直接终结
        done=true;
        return {value: arguments, done: done}
    }
    ----------------------------------------------------------------
    总结:generator的几个技术点
    
    1.field/ruturn转化为内部函数
    2.闭包,状态机
    2.返回内部函数的迭代器
    3.迭代及内部迭代(next方法,传参)
    4.迭代终结:会置done:true
        A:next迭代到return:除了会置done:true,和普通next无区别
        B:迭代器调用return:传参给自己用(毕竟调用的是return函数而不是next);可以随时终结
        C:木有办法终结内部迭代器,除非它自己迭代完了
    

    3.generator生成器 应用场景

    1.协程
    2.异步操作的同步化表达(要主动在异步的yield表达式,完成位置添加x.next()才会生效)
      拿await来说,其是没有等待的功能的
    

    五、async/await:generator的语法糖

    Es7语法

    awit说白一点:就是在yield表达式,表示完成的位置,主动调用x.next()
    所以,看起来就像同步编程一样
    
    async 函数对 Generator 函数的改进,体现在以下三点
    1.内置执行器
    2.更好的语义
    3.更广的适用性
    
    function f11(){
        return new Promise((resolve) => {
            setTimeout(()=>{
                console.log("f11执行")
                resolve();
            }, 2000);
        });
    }
    function f12(){
        return new Promise((resolve,reject) => {
            setTimeout(()=>{
                console.log("f12执行")
                reject();
            }, 4000);
        });
    }
    async function Fun5(){
        let a=await f11();
        let b=await f12().catch(()=>{console.log("f12的catch函数")});
        console.log("底下内容")
    }
    Fun5();
    //
    f11执行
    f12执行
    f12的catch函数
    底下内容
    

    相关文章

      网友评论

        本文标题:JavaScript之异步

        本文链接:https://www.haomeiwen.com/subject/gnmuwqtx.html