es6 Generator函数

Generator函数是ES6的异步编程解决方案,它是一个状态机并返回遍历器对象。通过.next()方法驱动函数执行,遇到yield即暂停并返回值。在实际应用中,Generator常用于处理多个Ajax请求的顺序执行问题,通过Promise与Generator结合,避免回调地狱。在async/await出现之前,Generator提供了一种自动化的解决方案。
摘要由CSDN通过智能技术生成

Generator函数

  • Generator函数是ES6提供的一种异步编程解决方案。
  • Generator函数是一个状态机,封装了多个内部状态。
  • 执行Generator函数会返回一个遍历器对象,也就是说,Generator函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历Generator函数内部的每一个状态。

1.基本语法
2.next的参数
3.Generator的实际应用

      function *gen(){ // Generator的写法
        console.log("111")
        yield //产出
        console.log("222")
        yield
        console.log("333")
      }
      gen()

使用*号即可生成Generator函数,但是上面的代码执行结果为空,控制台中什么也不会打印。因为Generator是不会主动执行的,它需要驱动,相当于给车加油,.next就是汽油。

      function *gen(){
        console.log("111")
        yield //产出
        console.log("222")
        yield
        console.log("333")
      }
      let g = gen()
      g.next()

这样就可以完美执行了吗,答案是不会
在这里插入图片描述
打印了111之后就不会继续执行了,因为碰到了yield,它相当于中断器,车开到这直接没油了,所以需要再次加油

      function *gen(){
        console.log("111")
        yield //产出
        console.log("222")
        yield
        console.log("333")
      }
      let g = gen()
      g.next()
      g.next()

执行结果
在这里插入图片描述
又碰到yield又没油了,再来一次

      function *gen(){
        console.log("111")
        yield //产出
        console.log("222")
        yield
        console.log("333")
      }
      let g = gen()
      g.next()
      g.next()
      g.next()

当三次调用.next函数才全部打印,继续调用next是不会继续打印的。
在这里插入图片描述
注意注释,我给yield标的一个产出,说明它不仅能中断,还能返回东西

      function *gen(){
        console.log("111")
        yield  "aaa"//产出
        console.log("222")
        yield  "bbb"
        console.log("333")
      }
      let g = gen()
      let res1 = g.next()
      console.log(res1)
      let res2 = g.next()
      console.log(res2)
      let res3 = g.next()
      console.log(res3)

在这里插入图片描述
这里可以发现,yield返回的结果像什么,Iterator迭代器,所以它一定是可以使用for of的。

        function* gen() {
            console.log("111")
            yield "aaa"//产出
            console.log("222")
            yield "bbb"
            console.log("333")
        }
        let g = gen()
        for (let i of g) {
            console.log(i)
        }
        let res1 = g.next()
        console.log(res1)
        let res2 = g.next()
        console.log(res2)
        let res3 = g.next()
        console.log(res3)

在这里插入图片描述
这里因为for of执行时调用了.next,所以后面在执行.next时,执行结果就为空了。
二、next的参数

        function* gen() {
           
            let res1 =  yield "aaa"
            console.log("gen函数内部",res1)
      
            let res2 = yield "bbb"
            console.log("gen函数内部",res2)
  
        }
        let g = gen()
        
        let res1 = g.next("next传入111")
        console.log(res1)

        let res2 = g.next("next传入222")
        console.log(res2)
        
        let res3 = g.next("next传入333")
        console.log(res3)

在这里插入图片描述
这里打印的结果让人摸不着头脑,慢慢看打印顺序,因为执行到第一个yield函数中断了,所以相当于把gen函数内部的“aaa”返回给外部的res1时,就中断了,给函数内部的res1赋值并没有完成,所以gen函数内部的res1需要第二个next参数传值才能有效赋值。所以第一个next的传参无意义。

三、Generator的实际应用

        function ajax(url){
            return new Promise((resolve,reject) => {
                let xhr = new XMLHttpRequest()
                xhr.open("get",url,true)
                xhr.send()
                xhr.onreadystatechange = function(){
                    if(xhr.readyState === 4){
                        if(xhr.status >= 200 && xhr.status<300){
                            resolve(JSON.parse(xhr.responseText))
                        }else{
                            reject(xhr.responseText)
                        }
                    }
                }
            })
        }

        function* gen(){
            let res1 = yield ajax("01.json")
            console.log("第一个请求的结果",res1)
            let res2 = yield ajax("02.json",res1)
            console.log("第二个请求的结果",res2)
        }

        let g = gen()
        g.next().value.then(data => {
            console.log(data,"这是ajax请求回来的数据")
            g.next(data).value.then(data2 => {
                console.log(data2,"这是ajax通过第一次请求回来的数据请求的第二次数据")
                g.next(data2)
            })
        })

上面的代码简单封装了一个ajax,和使用了json-server来模拟数据请求。模拟实现了在第一次请求后,通过第一次请求的数据发起下一次请求。
在这里插入图片描述
但是在调用next时,要一直循环嵌套,所以不可避免的又出现了回调地狱。这个问题由后面的 async和await解决,其实本质是一样的,async相当于yield,await相当于这了next,现在需要调用next进行手动驱动,而async,await相当于自动驱动,无非是手动挡变自动挡,但是原理是一样的。

        function ajax(url){
            return new Promise((resolve,reject) => {
                let xhr = new XMLHttpRequest()
                xhr.open("get",url,true)
                xhr.send()
                xhr.onreadystatechange = function(){
                    if(xhr.readyState === 4){
                        if(xhr.status >= 200 && xhr.status<300){
                            resolve(JSON.parse(xhr.responseText))
                        }else{
                            reject(xhr.responseText)
                        }
                    }
                }
            })
        }

        function* gen(){
            let res1 = yield ajax("01.json")
            console.log("第一个请求的结果",res1)
            let res2 = yield ajax("02.json",res1)
            console.log("第二个请求的结果",res2)
        }

        //手动版本
        // let g = gen()
        // g.next().value.then(data => {
        //     console.log(data,"这是ajax请求回来的数据")
        //     g.next(data).value.then(data2 => {
        //         console.log(data2,"这是ajax通过第一次请求回来的数据请求的第二次数据")
        //         g.next(data2)
        //     })
        // })
        
        //自动版本
        function AutoRun(gen){
            let g = gen();
            function next(data){
                let res = g.next(data);
                if(res.done) return 
                res.value.then(function (data) {
                    next(data);
                })
            }
            next()
        }
        AutoRun(gen)

在await出现之前的自动挡,可以说是相当好开了!!!后面的async和await其实就是对generator的封装而已,就是语法糖。
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值