Generator 和 Iterator:那些你不知道却一直在默默付出的幕后英雄
Iterator 和 Generator,是 JS 世界真正的幕后英雄
Generator 和 Iterator:那些你不知道却一直在默默付出的幕后英雄
当你用 for...of 遍历数组,当你写下一句优雅的 ...spread,当你轻松地用 async/await 管理异步流程——你可能从未意识到,在这些看似简单的语法糖背后,Quietly 工作的,正是 Iterator(迭代器) 与 Generator(生成器)。
它们不张扬、不喧嚣,却构成了现代 JavaScript“基础设施”的一部分。 如果没有它们,前端世界会瞬间变得粗糙、笨重、混乱。
今天,就让我们从“幕后工程师”的角度重新认识它们: 它们在哪里工作?工作得多辛苦?为什么我们几乎每天都在用它们,却意识不到?
一、你每天都在用它们:JS 的“通用插口”靠 Iterator 驱动
当你写下这些代码时:
for (const item of array) {}
[...set]
const [a, b] = array
Promise.all(iterable)
new Map(iterable)你以为你只是在用“语法”。 但其实,引擎偷偷做了这件事:
找对象的
Symbol.iterator,拿到一个“迭代器”,再一点一点把数据取出来。
Iterator 就像一个“统一数据访问协议”,JS 的各种数据结构——Array、Set、Map、String、TypedArray、arguments 等——只要提供这个接口,就能被 JS 所有遍历工具支持。
这意味着:
- 消费侧统一了:for...of 不用关心对象内部是什么结构
- 生产侧可自由扩展:任何对象只要定义
Symbol.iterator就能像数组一样被遍历
也就是说:
Iterator 在 JS 中扮演了一种类似 “USB 标准接口” 的角色 —— 所有东西,只要实现了它,就能即插即用。
它就是那个每天被插件、被调用、被 for...of 掏空,但从不抱怨的“底层劳动者”。
二、Generator:给普通函数装上一颗“心脏”
Generator 是 JS 中最被低估的能力之一。
它让函数具备了:
- 暂停
- 恢复
- 双向通信
- 惰性求值
- 无限数据生成
- 流程控制能力
如果把普通函数比作一段一口气跑完的录影带,那么 Generator 就是一段可暂停、可倒带、可插播、可互动的互动剧本。
看看它最核心的能力:
function* gen() {
console.log("start")
const name = yield "你的名字?"
const age = yield `你好 ${name}, 年龄?`
return `${name} / ${age}`
}
const g = gen()
g.next() // -> 暂停,等待用户输入
g.next("张三") // -> 把数据塞回函数中
g.next(22)是不是像协程?像状态机?像 async/await? 没错——async/await 的底层就是基于 Generator 模式演化而来(Promise + 自动执行器)。
Generator 的出现,让 JS 彻底撕掉了“单纯的脚本语言”的标签。
三、它们联手时更强:Generator = 可迭代对象的创造者
Generator 最大的隐藏技能之一:
它返回的对象,既是迭代器(iterator),又是可迭代对象(iterable)。
也就是说:
function* test() {
yield 1
yield 2
}
for (const v of test()) {} // 完美支持
[...test()] // 可以展开不要小看这一点—— 这意味着:你只写一个函数,就能同时支持所有 JS 遍历机制。
并且它还支持委托:
function* g1() { yield 1; yield 2; }
function* g2() { yield* g1(); yield 3; }看似简单,实际意义却是:
你可以用 Generator 拼接数据管线、分层数据读取、模块化数据流。
这就是为什么像 Redux-Saga 等大型库都 heavily 依赖 Generator。
四、它们在“那些你以为无关的地方”默默付出
这里是真相:
👇 你以为跟它们无关的地方,其实都靠它们撑着。
(1)展开运算符 ...
[...map]为了支持这行代码,JS 做了:
找 mapSymbol.iterator → 得到 entries 的迭代器 → 一个一个解构值
Iterator 完成 100% 的工作。
(2)解构赋值
const [a, b] = set解构过程是“迭代摄取”,底层完全依赖迭代器。
(3)Promise.all / Promise.race / Promise.allSettled
很多人不知道:
Promise.all 参数不是数组,是 iterable。 也就是说:你传 Set、Map、Generator 都可以。
Promise.all(new Set([p1, p2, p3]))完全依赖可迭代协议。
(4)for await...of(异步迭代器)
你以为 async iterator 很高级?
其实就是:
Iterator + Promise + 协议升级版
(5)async/await 的祖先 = Generator
async/await 的早期实现(如 co 库)如下:
function* task() {
const user = yield fetchUser()
const orders = yield fetchOrders(user.id)
return orders
}是不是很眼熟? 所以:
Generator 不是过时,而是“功成身退”,成为 async/await 的底层哲学。
五、现实中它们还做了哪些脏活累活?
处理大文件或无限数据(惰性读取)
Generator 可以做到:
读取 1GB 文件?No Problem → 一行一行 yield,不占内存。
复杂状态机
每一个 yield 天然是一个“状态节点”。
自定义数据流管道(类 RxJS)
过滤 → 映射 → 限流 → take(n) 全部用 generator 写,非常优雅。
六、总结:Iterator 和 Generator,是 JS 世界真正的幕后英雄
如果没有它们:
- for...of 会消失
- 展开运算符半废
- 解构能力大幅削弱
- Map/Set 构造能力倒退
- Promise.all 限制更多
- async/await 根本无法诞生
- 无限序列处理不可能
- Redux-Saga 不能用
- 你处理大文件会痛苦万分
它们是 JS 生态中的:
🏗 结构性基础设施 ⚙ 底层数据驱动器 🧵 控制流奠基者 🛠 高级语法的隐形支撑
周温
全栈开发工程师,专注于前端技术栈和物联网应用开发。拥有丰富的 React、Next.js、Nest.js 项目经验,擅长构建高性能、可扩展的 Web 应用。热爱技术分享,致力于将复杂的技术问题转化为易懂的实践指南。
相关文章
浏览相关文章,深入了解技术主题
前端救星:Mock、Express 与 JSON Server 助力前后端联调与独立开发
前端救星:在前端开发中,等待后端接口的日子,是所有前端工程师共同的噩梦,Mock、Express 与 JSON Server 助力前后端联调与独立开发。
开发小透明 & 面试大明星:Map 和 Set 的双面人生
开发小透明 & 面试大明星:Map 和 Set 的双面人生。 在 JavaScript 的江湖中,有两位常被误解的角色:* **开发中:小透明,不出场也没人想念它们*** **面试时:大明星,不问它都觉得不专业**
React Hooks 最佳实践指南
掌握 React Hooks 的正确使用方式,避免常见陷阱,编写更清晰、更高效的 React 代码。