美文网首页面试题
ES6中Generator函数的用法

ES6中Generator函数的用法

作者: 易路先登 | 来源:发表于2019-06-22 03:05 被阅读0次

    Generator 函数是 ES6 提供的一种异步编程解决方案,也是遍历器生成函数,语法行为与传统函数完全不同。

    1 基本用法

    使用function关键字后加*的方式声明一个函数,该函数即为Generator函数

    let tell = function* (){
        yield 1;
        yield 2;
        yield 3;
    }
    let k = tell();
    console.log(k.next());//{value: 1, done: false}
    console.log(k.next());//{value: 2, done: false}
    console.log(k.next());//{value: 3, done: false}
    console.log(k.next());//{value: undefined, done: true}
    

    由上面代码可知,Generator函数有多个返回值状态(每个yield关键字后跟一个状态),只有调用next()函数时才会返回值,每调用一次next()函数就返回一个对象{value: xxx, done: false},直到没有对应的yield了就返回done状态为true的对象{value: undefined, done: true}

    2 添加遍历器

    一个普通的对象obj默认是没有遍历器的,意味着不能使用for...of遍历,且不能使用...操作符解构。

    let obj = {
        name:'zhangsan',
        age:18,
        sex:'man'
    }
    for(var value of obj){
      console.log(value);//报错 obj is not iterable
    }
    console.log([...obj]);//报错 obj is not iterable
    

    可见都是报错obj is not iterable,我们通过Generator函数给其添加遍历器。

    let obj = {
        name:'zhangsan',
        age:18,
        sex:'man'
    }
    obj[Symbol.iterator]=function* (){
        for(var key in obj){
            yield obj[key];
        }
    }
    for(let value of obj){
        console.log(value);//zhangsan 18 man
    }
    console.log([...obj]);//["zhangsan", 18, "man"]
    
    3 将ajax请求转成类似的 let a = ajax()的同步赋值形式

    经常碰见一个业务内多个请求串联依赖,即后者依赖前者的请求结果,目前只能有两种做法,

    • 回调函数嵌套
    • 使用promise的.then进行链式调用
      但现在我们学习了Generator函数后可以有第三种选择
    • 将前一个网络请求的返回值赋值给一个变量,在下一个请求中使用
      即以下形式:
      let a = 请求1(){}
      let b = 请求2(a){}
      实现代码如下:
    let res = 0;
    //封装一个网络请求函数,不做实际动作,就打印一下参数param
    function ajaxMy(method,url,param,varibal){
        console.log(param);
        //使用延时计时器模拟网络请求1秒后返回正确结果response
        setTimeout(function(){
            let response = res++;
            varibal.next(response);
        },300)
    }
    
    let k;
    let tell = function* (){
        //网络请求1
        let a = yield ajaxMy('get','www.baidu.com',10,k);
        console.log(a);//0
        //网络请求2
        let b = yield ajaxMy('get','www.baidu.com',a,k);
        console.log(b);//1
        //网络请求3
        let c = yield ajaxMy('get','www.baidu.com',b,k);
        console.log(c);//2
        //网络请求4
        let d = yield ajaxMy('get','www.baidu.com',c,k);
        console.log(d);//3
    }
    k = tell()
    k.next();
    

    以上代码let a = yield ajaxMy('get','www.baidu.com',10,k);类似于将一个网络请求的返回值赋值给了a变量,可在下一步请求yield ajaxMy('get','www.baidu.com',a,k);中作为参数使用,这样一来编写业务逻辑就会清晰很多

    4 实现状态机
    let state = function* (){
        while(1){
            yield 'block';
            yield 'none';
        }
    }
    let displayClass = state();
    console.log(displayClass.next().value);//block
    console.log(displayClass.next().value);//none
    console.log(displayClass.next().value);//block
    console.log(displayClass.next().value);//none
    

    每调用一次next,value值会在block,none两值之中来回切换,且不会被篡改。

    5 实现轮询
    //请求方法,返回值包括状态码和数据
    let requestSingFn = function* (){
        yield new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve({code:304,data:{username:'zhangsan'}});
            },300)
        })
    }
    //轮询函数 只有当code为200时才会停止发送请求
    let requestFn = function(){
        let req = requestSingFn();
        let stat = req.next();
        stat.value.then(function(response){
            if(response.code!=200){
                setTimeout(function(){
                    console.log('重新发送请求');
                    requestFn();
                },1000);
            }else{
                console.log(response.data);
            }
        })
    }
    requestFn();
    

    async函数的优势:

    1、不用通过执行器去触发程序往下走
    2、参数传递特别方便,await会等待后续promise函数执行完成,将结果取出,才接着往下走。

    function promise1(){
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve(16)
            },1000)
        })
    }
    function promise2(){
        let var1 = await promise1();//确定是否登陆
        return new Promise((resolve,reject)=>{
            setTimeout(()=>{
                resolve(160)
            },1000)
        })
    }
    async function myasyncFn(){
        let var1 = await promise1();//确定是否登陆
        console.log(var1,'-------')
        let var2 = await promise2();//如果已经登陆,去请求数据
        console.log(var2)
        return var2
    }
    let myreturn = myasyncFn()
    myreturn.then((res)=>{
        //用户利用最终返回值去完成自己的业务逻辑
        console.log(res,'最终返回值')
    })
    

    只有当code的状态变为200成功响应才会停止发送请求,否则每个1300毫秒发送一次请求
    ES6总篇--目录

    相关文章

      网友评论

        本文标题:ES6中Generator函数的用法

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