JavaScript 异步 迭代器与生成器(Iterators & Generators
·

JavaScript 迭代器、生成器、yield、惰性计算、无限序列与异步生成器,是进阶异步与数据流编程的核心基础。
一、开篇:能暂停的函数
如果一个函数可以执行到一半暂停、返回一个值,之后再从暂停处恢复执行,会怎样?如果能创建一个按需计算的序列(而非一次性全部生成),又会怎样?
// 可以暂停、恢复的函数
function* countToThree() {
yield 1 // 暂停,返回 1
yield 2 // 恢复,暂停,返回 2
yield 3 // 恢复,暂停,返回 3
}
const counter = countToThree()
console.log(counter.next().value) // 1
console.log(counter.next().value) // 2
console.log(counter.next().value) // 3
这就是生成器(Generator)。ES2015 引入,配合迭代器,实现:
- 惰性求值
- 无限序列
- 清晰的数据管道
- 可控的暂停 / 恢复执行
二、本文你将学到
- 迭代器与迭代协议
- 生成器函数
function*与yield yield与return的区别- 用
Symbol.iterator让任何对象可迭代 - 惰性求值与内存效率
- 分页、ID 生成、状态机等实战模式
- 异步生成器与
for await...of
前置知识:闭包、高阶函数
三、什么是迭代器(Iterator)?
迭代器是一个对象,表示一个序列,提供逐个取值的方法。必须具备 .next() 方法,返回结构:
js
{ value: 下一个值, done: 是否结束 }
示例:手动实现迭代器
function createCounterIterator(max) {
let count = 0
return {
next() {
if (count < max) {
return { value: count++, done: false }
} else {
return { value: undefined, done: true }
}
}
}
}
为什么用迭代器?
- 惰性求值:用到才计算,不预先全量生成
- 极高内存效率:不用把整个序列放入内存
四、可迭代对象(Iterable)
实现了 Symbol.iterator 方法的对象,就是可迭代的。
JS 内置可迭代对象
- Array
- String
- Map
- Set
- arguments
- NodeList
for...of、展开运算符、解构 底层都用迭代器。
五、售货机类比(生成器最易懂的比喻)
你 = 调用者售货机 = 生成器
- 按按钮 → 调用
.next() - 掉出一个商品 →
yield返回值 - 机器暂停等待 → 生成器暂停
- 记住位置 → 生成器保存状态
- 卖完 →
done: true
六、什么是生成器(Generator)?
生成器是可以暂停和恢复执行的函数。
- 声明:
function*(带星号) - 暂停:
yield - 恢复:
.next()
关键特性
调用生成器函数不会立刻执行,只返回一个生成器对象(迭代器)。只有调用 .next() 才会执行到下一个 yield。
七、yield 深度解析
基础用法
function* demo() {
console.log('开始')
yield '第一个值'
console.log('恢复')
yield '第二个值'
console.log('结束')
return '完成'
}
yield vs return
| 特性 | yield | return |
|---|---|---|
| 作用 | 暂停生成器 | 终止生成器 |
| done 状态 | false | true |
| 数量 | 可以多个 | 只有最后一个有效 |
| for...of 可见 | 可见 | 不可见 |
注意:return 的值不会被 for...of/ 展开运算符捕获。
八、yield*:委托迭代
把另一个可迭代对象的结果全部 yield 出来。常用于递归展开、嵌套结构扁平化。
function* inner() { yield 'a'; yield 'b' }
function* outer() { yield 1; yield* inner(); yield 2 }
console.log([...outer()]) // [1,'a','b',2]
九、向生成器内部传值
可以通过 .next(值) 把数据传入生成器,成为上一个 yield 的返回值。
function* chat() {
const name = yield '你叫什么名字?'
yield `你好,${name}!`
}
const gen = chat()
gen.next().value // "你叫什么名字?"
gen.next('Alice').value // "你好,Alice!"
十、生成器控制方法
1. .return(值)
立刻终止生成器
gen.return('终止') // { value:'终止', done:true }
2. .throw(错误)
在当前 yield 位置抛出错误
gen.throw(new Error('出错啦'))
十一、迭代协议(核心)
让自定义对象支持 for...of、展开运算符,只需实现:
[Symbol.iterator]() {
return 迭代器
}
极简写法(用生成器)
const obj = {
items: [1,2,3],
*[Symbol.iterator]() {
yield* this.items
}
}
for(let x of obj) console.log(x)
十二、惰性求值 & 无限序列
生成器最强大的能力:用到才计算。
无限序列(数组不可能做到)
function* naturalNumbers() {
let n = 1
while(true) yield n++
}
只取前 N 个
function* take(n, iter) {
let count = 0
for(const v of iter) {
if(count++ >= n) return
yield v
}
}
十三、五大实战模式
1. 唯一 ID 生成器
function* createId(prefix) {
let id = 1
while(true) yield `${prefix}_${id++}`
}
2. 分页 / 分块处理
function* chunk(arr, size) {
for(let i=0; i<arr.length; i+=size) {
yield arr.slice(i, i+size)
}
}
3. 数据管道:filter + map
function* filter(iter, fn) { for(const v of iter) if(fn(v)) yield v }
function* map(iter, fn) { for(const v of iter) yield fn(v) }
4. 状态机(红绿灯)
function* light() {
while(true) {
yield 'green'
yield 'yellow'
yield 'red'
}
}
5. 树结构遍历(递归生成器)
function* traverse(node) {
yield node.value
if(node.children) for(const c of node.children) yield* traverse(c)
}
十四、异步生成器(Async Generator)
同步生成器只能同步值,异步生成器可以 await 并逐一流出异步数据。
语法
async function* fetchPages() {
let page = 1
while(true) {
const res = await fetch(`/api?page=${page++}`)
const data = await res.json()
if(!data.items) return
yield data.items
}
}
消费
for await (const items of fetchPages()) {
console.log(items)
}
适用场景:
- 分页接口流式读取
- 文件逐行读取
- 流式处理大数据
- 数据库游标
十五、常见错误(高频坑)
- 忘记写
function*的星号 → SyntaxError - 调用生成器不执行 → 必须
.next()或迭代 - 用 return 给迭代传值 → for...of 拿不到
- 耗尽的生成器重复使用 → 返回空
- 无限生成器直接展开 → 卡死
[...forever()] - 小数据量用生成器 → 数组更简单
十六、核心总结
- 迭代器:
.next()→{value,done} - 生成器:
function*+yield→ 可暂停函数 yield暂停,return终止yield*委托迭代- 惰性求值 = 高性能 + 无限序列
Symbol.iterator→ 让对象可迭代- 异步生成器:
async function*+for await...of
📦 概念 汇总
1. 核心基础
- 迭代器 Iterator同类:遍历器、序列访问器、游标
- 生成器 Generator同类:协程、暂停函数、可中断函数
- 迭代协议 Iterable Protocol同类:可遍历接口、统一遍历标准
- Symbol.iterator同类:内置迭代入口、遍历工厂
2. 语法与关键字
- function*同类:生成器声明、协程函数
- yield同类:暂停、产出、挂起
- yield*同类:委托迭代、展开迭代、递归遍历
- .next()同类:步进、恢复执行
- .return()同类:终止、关闭、清理
- .throw()同类:错误注入、异常触发
3. 求值与性能
- 惰性求值 Lazy Evaluation同类:按需计算、延迟计算、按需加载
- 急切求值 Eager Evaluation同类:预先计算、全量生成
- 无限序列 Infinite Sequence同类:无限流、无穷数列、无界迭代
4. 流程模式
- 数据管道 Data Pipeline同类:链式处理、流操作、filter/map
- 状态机 State Machine同类:流程控制、状态流转、步骤执行
- 分页生成器同类:分批加载、懒加载、游标分页
- 扁平化遍历同类:递归展开、树摊平、深度遍历
5. 异步扩展
- 异步生成器 Async Generator同类:异步流、异步迭代器
- for await...of同类:异步遍历、流消费
- 流式处理 Streaming同类:逐块处理、渐进式加载
6. 上层关联(你学过的)
- Promise同类:异步结果占位符
- async/await同类:协程、暂停恢复(基于 Promise)
- 回调 Callback同类:异步控制(旧式)
- 事件循环同类:任务调度、异步执行

更多推荐

所有评论(0)