JavaScript基本功之生成器(generator)

生成器是什么

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

demo: 生成器的迭代

  • for-of 遍历
js 复制代码
// for-of迭代遍历
function * gen(){    
    yield "小学生"; // 相当于执行next()返回 {value: '小学生', done: false} 
    yield "中学生" 
    yield "大学生" 
}                 

// TEST 
for (const v of gen()) {
  console.log('v=',v)
}
// v= 小学生
// v= 中学生
// v= 大学生

demo:生成器执行next

  • yield的参数是next方法的返回值
  • yield 把代码分成N段执行
  • next 方法可以分段执行
js 复制代码
// 定义生成器函数
// 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}

demo:生成器yield的返回值

  • next方法的参数是yield的返回值
  • 第N个next方法的参数是N-1个yield的返回值
js 复制代码
// 定义生成器函数
// 第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

demo: 异步任务同步化表达

  • 需求: 按顺序获取异步请求的结果
  • 顺序: 用户数据-》订单数据-》商品数据
  • 异步: 使用 settimout 模拟
js 复制代码
// 使用回调方式执行: 回调地狱
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) ['用户数据', '订单数据', '商品数据']
js 复制代码
// 使用生成器方式执行: 执行顺序更清晰
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) ['用户数据', '订单数据', '商品数据']

demo: 生成器和迭代器结合

js 复制代码
// 遍历扑克牌 
// 生成器和迭代器结合使用 
// 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']
相关推荐
shinelord明1 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
Monly218 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
boligongzhu9 分钟前
DALSA工业相机SDK二次开发(图像采集及保存)C#版
开发语言·c#·dalsa
Eric.Lee20219 分钟前
moviepy将图片序列制作成视频并加载字幕 - python 实现
开发语言·python·音视频·moviepy·字幕视频合成·图像制作为视频
7yewh12 分钟前
嵌入式Linux QT+OpenCV基于人脸识别的考勤系统 项目
linux·开发语言·arm开发·驱动开发·qt·opencv·嵌入式linux
长风清留扬14 分钟前
小程序毕业设计-音乐播放器+源码(可播放)下载即用
javascript·小程序·毕业设计·课程设计·毕设·音乐播放器
waicsdn_haha23 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
_WndProc25 分钟前
C++ 日志输出
开发语言·c++·算法
m0_7482478028 分钟前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
qq_4335545434 分钟前
C++ 面向对象编程:+号运算符重载,左移运算符重载
开发语言·c++