• JavaScript基本功之生成器(generator)


    生成器是什么

    • 是一个特殊函数,特殊的迭代器(Iterator)
    • 定义: 函数名前有星号,内部使用 yield 语法
    • 返回: 内部包含next方法的迭代器
    • 执行: 通过调用 next() 方法消耗生成器,直至遇到 yield 关键字。
    // 定义生成器函数
    function * gen(){
        console.log('hello generator!')
    }
    // 生成器函数返回
    let genResult = gen()
    console.log('genResult=',genResult)
    // // genResult=gen{} 内部包含Prototype-next(function)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    demo: 生成器的迭代

    • for-of 遍历
    // for-of迭代遍历
    function * gen(){    
        yield "小学生"; // 相当于执行next()返回 {value: '小学生', done: false} 
        yield "中学生" 
        yield "大学生" 
    }                 
    
    // TEST 
    for (const v of gen()) {
      console.log('v=',v)
    }
    // v= 小学生
    // v= 中学生
    // v= 大学生
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    demo:生成器执行next

    • yield的参数是next方法的返回值
    • yield 把代码分成N段执行
    • next 方法可以分段执行
    // 定义生成器函数
    // yield 把代码分成4段执行
    function * gen(){
        console.log('111')
        yield "小学生"; // 第1段
        console.log('222')
        yield "中学生" // 第2段
        console.log('333')
        yield "大学生" // 第3段
        console.log('444')
    }                 // 第4段
    
    // TEST 
    let g = gen()
    console.log('g.next()=',g.next())
    // 111
    // g.next()= {value: '小学生', done: false}
    console.log('g.next()=',g.next())
    // 222
    // g.next()= {value: '中学生', done: false}
    console.log('g.next()=',g.next())
    // 333
    // g.next()= {value: '大学生', done: false}
    console.log('g.next()=',g.next())
    // 444
    // g.next()= {value: undefined, done: true}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    demo:生成器yield的返回值

    • next方法的参数是yield的返回值
    • 第N个next方法的参数是N-1个yield的返回值
    // 定义生成器函数
    // 第N个next方法的参数是N-1个yield的返回值
    function * gen(){    
        const one = yield "小学生"
        console.log('one=',one)
        const two = yield "中学生" 
        console.log('two=',two)
        const three = yield "大学生" 
        console.log('three=',three)
    }                 
    
    // TEST 
    const g = gen()
    g.next();
    g.next('AAA'); // 第2个next是第1个yield的返回值
    g.next('BBB'); // 第3个next是第2个yield的返回值
    g.next('CCC'); // 第4个next是第3个yield的返回值
    // one= AAA
    // two= BBB
    // three= CCC
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    demo: 异步任务同步化表达

    • 需求: 按顺序获取异步请求的结果
    • 顺序: 用户数据-》订单数据-》商品数据
    • 异步: 使用 settimout 模拟
    // 使用回调方式执行: 回调地狱
    function getData() {
      let result = []
      setTimeout(() => {
        result.push('用户数据')
        setTimeout(() => {
          result.push('订单数据')
          setTimeout(() => {
            result.push('商品数据')
            consumeData(result)
          }, 500)
        }, 500);
      }, 500)
    }
    function consumeData(data) {
      console.log('data=', data)
    }
    getData()
    // getData start...
    // getUsers
    // getOrders
    // getGoods
    // getData end...
    // consumeData data= (3) ['用户数据', '订单数据', '商品数据']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    // 使用生成器方式执行: 执行顺序更清晰
    let result = []
    function getUsers() {
        setTimeout(() => {
            console.log('getUsers...')
            result.push('用户数据')
            iter.next() // 2.执行 getOrders
        }, 500)
    }
    function getOrders() {
        setTimeout(() => {
            console.log('getOrders...')
            result.push('订单数据')
            iter.next()  // 3.执行 getGoods
        }, 500)
    }
    function getGoods() {
        setTimeout(() => {
            console.log('getGoods...')
            result.push('商品数据')
            iter.next() // 4.执行getGoods在getData后面的代码
            consumeData(result)
        }, 500)
    }
    function* getData() {
        console.log('getData start')
        yield getUsers()
        yield getOrders()
        yield getGoods()
        console.log('getData end')
    }
    
    function consumeData(data) {
        console.log('consumeData data=', data)
    }
    
    let iter = getData()
    iter.next() // 1.执行 getUsers
    // getData start
    // getUsers...
    // getOrders...
    // getGoods...
    // getData end
    // consumeData data= (3) ['用户数据', '订单数据', '商品数据']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    demo: 生成器和迭代器结合

    // 遍历扑克牌 
    // 生成器和迭代器结合使用 
    // yield 相当于 next 方法 
    const cards = {
      suits: ["♣️", "♦️", "♥️", "♠️"],
      courts: ["J", "Q", "K", "A"],
      [Symbol.iterator]:function*(){ // 迭代器+生成器
        for(let s of this.suits){
          for (let i = 2; i < 10; i++) yield s+i 
          for(let c of this.courts) yield s+c
        }
      }
    }
    
    // TEST1 for-of 遍历
    let result = []
    for (const v of cards) {
      result.push(v)
    }
    console.log('result=',result)
    // result= (48) ['♣️2', '♣️3', '♣️4', '♣️5', '♣️6', '♣️7', '♣️8', '♣️9', '♣️J', '♣️Q', '♣️K', '♣️A', '♦️2', '♦️3', '♦️4', '♦️5', '♦️6', '♦️7', '♦️8', '♦️9', '♦️J', '♦️Q', '♦️K', '♦️A', '♥️2', '♥️3', '♥️4', '♥️5', '♥️6', '♥️7', '♥️8', '♥️9', '♥️J', '♥️Q', '♥️K', '♥️A', '♠️2', '♠️3', '♠️4', '♠️5', '♠️6', '♠️7', '♠️8', '♠️9', '♠️J', '♠️Q', '♠️K', '♠️A']
    
    // TEST2 解构赋值
    console.log('cards=',[...cards])
    // cards= (48) ['♣️2', '♣️3', '♣️4', '♣️5', '♣️6', '♣️7', '♣️8', '♣️9', '♣️J', '♣️Q', '♣️K', '♣️A', '♦️2', '♦️3', '♦️4', '♦️5', '♦️6', '♦️7', '♦️8', '♦️9', '♦️J', '♦️Q', '♦️K', '♦️A', '♥️2', '♥️3', '♥️4', '♥️5', '♥️6', '♥️7', '♥️8', '♥️9', '♥️J', '♥️Q', '♥️K', '♥️A', '♠️2', '♠️3', '♠️4', '♠️5', '♠️6', '♠️7', '♠️8', '♠️9', '♠️J', '♠️Q', '♠️K', '♠️A']
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    存储压测工具— — Cosbench教程
    Fama-French三因子和五因子模型和Stata代码(内附原始数据)
    【生日快乐】SpringBoot SpringBoot 提高篇(第二篇) 第5章 SpringBoot 日志 5.4 日志格式
    Schrodinger Shape Screen 工具使用方法
    rsync同步目录脚本
    Java Day2(Java基础语法)
    [ C++ ] 一篇带你了解C++中动态内存管理
    【大数据之Kafka】十五、Kafka-Kraft模式
    HTML
    SpringBoot定义优雅全局统一Restful API 响应框架六
  • 原文地址:https://blog.csdn.net/qubes/article/details/134329711