面试题

ES6中Generator函数的用法

2019-06-22  本文已影响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()的同步赋值形式

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

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总篇--目录

上一篇下一篇

猜你喜欢

热点阅读