Generator 函数的用法和通过它封装一个async函数

1.什么是Generator函数?

    Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。
Generator函数有多种理解角度。从语法上,首先可以把它理解成,Generator函数一个状态机,封装了多个内部状态。
执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还是一个遍历器对象生成函数。
形式上,Generator函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号,二是,函数体内部使用yield语句,定义不同的内部状态。(yield语句在英语里的意思就是“产出”)

// 这里定义了一个Generator 函数fn
function*fn(){
    yield 1;
    yield 2;
    yield 3;
}

2.Generator函数的调用

 在一篇前端中迭代器的理解和手动封装一个迭代器我们介绍了迭代,而Generator函数就是一个可迭代的函数。调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后每次调用遍历器对象的next方法,就会返回一个有着valuedone两个属性的对象。value属性表示当前的内部状态的值,是yield语句后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。

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

 

  • next 方法的作用是分阶段执行 Generator 函数。每次调用 next 方法,会返回一个对象,表示当前阶段的信息( value 属性和 done 属性)。
  • value 属性是 yield 语句后面表达式的值,表示当前阶段的值;
  • done 属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段(done为false 继续执行)

3.基于Generator 函数封装一个async函数

    通过上面的了解,大家也大致熟悉了Generator 函数,每次的next方法的执行就是返回yield语句后面的值或者表达式的值,基于这我们来把上面的fn给改写下。

function*fn(){
    yield new Promise((resolve,reject)=> {
         setTimeout(()=> {
             console.log(1)
             resolve()
         },500)
    });
    yield new Promise((resolve,reject)=> {
        setTimeout(()=> {
            console.log(2)
            resolve()
        },500)
   });
    yield new Promise((resolve,reject)=> {
        setTimeout(()=> {
            console.log(3)
            resolve()
        },500)
   });
}
let f = fn();
for(let fn of f){    //  注意 我这里是用的for of来调用
    console.log(fn)
}

来看下执行的结果:

当我们通过for of来调用执行的时候,它是一次执行完,很明显没有达到我们想要的依次执行,上一个执行才执行下一个。

这时我们就需要自己来封装一个co方法来实现依次调用的过程。

function*fn(){
    yield new Promise((resolve,reject)=> {
         setTimeout(()=> {
             console.log(1)
             resolve()
         },500)
    });
    yield new Promise((resolve,reject)=> {
        setTimeout(()=> {
            console.log(2)
            resolve()
        },500)
   });
    yield new Promise((resolve,reject)=> {
        setTimeout(()=> {
            console.log(3)
            resolve()
        },500)
   });
}
co(fn);
function co(fn){
    let f = fn()   // f是fn()执行的结果  也就是一个可迭代的
    next()
    function next(){
       let result =  f.next();    //  上一个执行完毕才执行下一个
       console.log(result)
    }
}

执行结果:

此时我们可以拿到第一个执行的结果,还有一个done属性,也就表示这个执行的结果,

通过这个属性我们可以判断有没有执行完毕;所以此时我们只用来进行对这个done属性判断他的true或者false就可以

得知执行的结果和是否开始执行下一个;

function*fn(){
    yield new Promise((resolve,reject)=> {
         setTimeout(()=> {
             console.log(1)
             resolve()
         },500)
    });
    yield new Promise((resolve,reject)=> {
        setTimeout(()=> {
            console.log(2)
            resolve()
        },500)
   });
    yield new Promise((resolve,reject)=> {
        setTimeout(()=> {
            console.log(3)
            resolve()
        },500)
   });
}
co(fn);
function co(fn){
    let f = fn()
    next()
    function next(){
       let result =  f.next();
       if(!result.done){
          // 上边一个异步走完  在执行下一个异步  
          result.value.then(()=> {     //上一个异步执行是否完毕我们可以通过是否调用.then方法判断
                 next()    // 执行完之后我们来调用下一个异步执行方法
          })
       }
       console.log(result)
    }
}

其执行结果:

到这里,我们的一个简单的async异步函数就已经封装好了,但是有些时候上一个异步执行完会传递一些数据到下一个

异步来使用,我们在来完善一下。

function*fn(){
    yield new Promise((resolve,reject)=> {
         setTimeout(()=> {
             console.log('a')
             resolve(1)
         },500)
    });
    yield new Promise((resolve,reject)=> {
        setTimeout(()=> {
            console.log('b')
            resolve(2)
        },500)
   });
    yield new Promise((resolve,reject)=> {
        setTimeout(()=> {
            console.log('c')
            resolve(3)
        },500)
   });
}
co(fn);
function co(fn){
    let f = fn()
    next()
    function next(data){   
       let result =  f.next();
       if(!result.done){
          // 上边一个异步走完  在执行下一个异步  
          result.value.then((info)=> {     //上一个异步执行是否完毕我们可以通过是否调用.then方法判断
            console.log(info,data)     
            next(info)    // 执行完之后我们来调用下一个异步执行方法
          })
       }
    }
}

其执行结果:

我们可以看到第一次的时候data是没有的,后面的data就是其上次执行的结果。

总结: generator函数它是我们目前所用的async /await的前身,而async /await又是 generator函数的语法糖。目前

 generator函数基本已经废弃掉了,很少的使用也是在封装一些源码的时候才会使用,这里主要就是通过generator函数

来让大家更加进一步的了解async /await,毕竟目前处理异步函数async /await才是老大。

 

 

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值