7. 你是怎么理解ES6中 Generator的?使用场景?
Generator 函数通过function*定义,内部使用yieldconsole.log('开始')yield 1console.log('继续')yield 2console.log('结束')return 3yield item你是否知道Generator 的语法和执行机制你能不能说清楚可暂停恢复、双向通信这些核心特性你是否理解Generator 和 async/await 的关系你能不能
一、面试开场怎么答更有层次
如果面试官问:
你怎么理解 ES6 中的 Generator?有什么使用场景?
不要直接说"Generator 是一种特殊函数"。
更好的开场方式是从 它的本质能力 说起:
Generator 是 ES6 引入的一种特殊函数,它最核心的能力是:可以暂停执行和恢复执行。
普通函数一旦开始执行就会一直运行到结束,而 Generator 可以在执行过程中通过yield暂停,把控制权交回给调用方,等调用方再次调用时继续执行。
这种"可中断、可恢复"的特性,让它在处理异步流程、惰性求值、状态机等场景下非常有用。
这个开场就很有深度。
二、什么是 Generator?
1)基本语法
Generator 函数通过 function* 定义,内部使用 yield 暂停:
function* gen() {
console.log('开始')
yield 1
console.log('继续')
yield 2
console.log('结束')
return 3
}
调用方式
const g = gen()
console.log(g.next()) // { value: 1, done: false }
console.log(g.next()) // { value: 2, done: false }
console.log(g.next()) // { value: 3, done: true }
关键点
- 调用 Generator 函数不会立即执行,而是返回一个遍历器对象(Iterator)
- 每次调用
.next()才会执行到下一个yield yield后面的值会作为.next()返回对象的valuedone: true表示函数执行完毕
2)执行流程图解
function* gen() {
console.log('step 1')
yield 'a'
console.log('step 2')
yield 'b'
console.log('step 3')
return 'c'
}
const g = gen()
| 调用 | 输出 | 返回值 |
|---|---|---|
g.next() |
step 1 |
{ value: 'a', done: false } |
g.next() |
step 2 |
{ value: 'b', done: false } |
g.next() |
step 3 |
{ value: 'c', done: true } |
面试加分说法
Generator 函数的执行是"惰性"的,只有调用
.next()才会推进执行,这和普通函数"一次性执行完"完全不同。
三、Generator 的核心特性
这是面试里最容易拉开差距的部分。
1)可暂停、可恢复
这是 Generator 最本质的特性。
function* gen() {
yield 1
yield 2
yield 3
}
const g = gen()
g.next() // 执行到第一个 yield
// 可以做其他事情
g.next() // 继续执行到第二个 yield
意义
- 可以把一个长任务拆成多个步骤
- 每一步可以由外部控制何时执行
- 适合处理需要"分段执行"的逻辑
2)yield 可以传值,.next() 也可以传值
这是很多人容易忽略的高级用法。
yield 向外传值
function* gen() {
yield 1
yield 2
}
const g = gen()
console.log(g.next().value) // 1
console.log(g.next().value) // 2
.next() 向内传值
function* gen() {
const a = yield 1
console.log('a =', a)
const b = yield 2
console.log('b =', b)
}
const g = gen()
g.next() // 执行到第一个 yield
g.next(10) // 把 10 传给 a,输出 a = 10
g.next(20) // 把 20 传给 b,输出 b = 20
理解
.next(value)传入的值,会作为上一个yield表达式的返回值。
这让 Generator 内外可以双向通信。
面试加分点
Generator 不只是单向输出数据,它还可以通过
.next(value)接收外部传入的值,形成双向数据流。
3)Generator 返回的是 Iterator
Generator 函数返回的对象,符合 Iterator 协议:
function* gen() {
yield 1
yield 2
yield 3
}
const g = gen()
// 可以用 for...of 遍历
for (const value of g) {
console.log(value) // 1, 2, 3
}
意义
- Generator 天然可迭代
- 可以配合
for...of、扩展运算符...、解构等使用
const arr = [...gen()] // [1, 2, 3]
4)yield* 委托给另一个 Generator
function* gen1() {
yield 1
yield 2
}
function* gen2() {
yield 'a'
yield* gen1()
yield 'b'
}
const g = gen2()
console.log([...g]) // ['a', 1, 2, 'b']
理解
yield*相当于把另一个 Generator 的所有yield展开到当前位置。
四、Generator 的使用场景
这是面试里很想听到的内容,要结合实际说。
1)异步流程控制(历史意义)
这是 Generator 最早被广泛使用的场景。
传统回调地狱
ajax(url1, function(res1) {
ajax(url2, function(res2) {
ajax(url3, function(res3) {
// ...
})
})
})
用 Generator + co 库
function* fetchData() {
const res1 = yield ajax(url1)
const res2 = yield ajax(url2)
const res3 = yield ajax(url3)
console.log(res1, res2, res3)
}
co(fetchData)
理解
Generator 可以让异步代码写得像同步一样,每个
yield等待异步结果返回后再继续。
这是async/await出现之前,社区用 Generator 实现异步流程控制的经典方案。
面试加分说法
Generator 在异步流程控制上的价值,主要是历史意义。
它启发了async/await的设计,async/await本质上就是 Generator + Promise 的语法糖。
现在我们更多直接用async/await,但理解 Generator 有助于理解async/await的底层原理。
这句话非常加分。
2)惰性求值 / 无限序列
Generator 可以生成"按需计算"的序列,不需要一次性生成所有值。
无限序列
function* fibonacci() {
let a = 0, b = 1
while (true) {
yield a
;[a, b] = [b, a + b]
}
}
const fib = fibonacci()
console.log(fib.next().value) // 0
console.log(fib.next().value) // 1
console.log(fib.next().value) // 1
console.log(fib.next().value) // 2
console.log(fib.next().value) // 3
优点
- 不会一次性占用大量内存
- 按需计算,性能更好
- 可以表达无限序列
面试加分点
Generator 的惰性特性,让它非常适合处理大数据集或无限序列,因为它不需要一次性把所有数据加载到内存。
3)状态机
Generator 天然适合实现状态机。
function* stateMachine() {
while (true) {
console.log('状态 A')
yield
console.log('状态 B')
yield
console.log('状态 C')
yield
}
}
const sm = stateMachine()
sm.next() // 状态 A
sm.next() // 状态 B
sm.next() // 状态 C
sm.next() // 状态 A(循环)
适用场景
- 游戏状态切换
- 流程控制
- 动画帧控制
4)遍历复杂数据结构
比如遍历树结构:
function* traverseTree(node) {
yield node.value
if (node.children) {
for (const child of node.children) {
yield* traverseTree(child)
}
}
}
const tree = {
value: 1,
children: [
{ value: 2 },
{ value: 3, children: [{ value: 4 }] }
]
}
console.log([...traverseTree(tree)]) // [1, 2, 3, 4]
5)实现自定义迭代器
const obj = {
data: [1, 2, 3],
*[Symbol.iterator]() {
for (const item of this.data) {
yield item
}
}
}
console.log([...obj]) // [1, 2, 3]
6)控制并发数量
比如控制同时只能有 N 个请求:
function* limitConcurrency(tasks, limit) {
const executing = []
for (const task of tasks) {
const p = task()
executing.push(p)
if (executing.length >= limit) {
yield Promise.race(executing)
executing.splice(executing.findIndex(e => e === p), 1)
}
}
}
五、Generator 和 async/await 的关系
这是面试高频追问。
1)async/await 是 Generator 的语法糖
// Generator 写法
function* fetchData() {
const res1 = yield fetch(url1)
const res2 = yield fetch(url2)
return res2
}
// async/await 写法
async function fetchData() {
const res1 = await fetch(url1)
const res2 = await fetch(url2)
return res2
}
对比
| 对比 | Generator | async/await |
|---|---|---|
| 语法 | function* + yield |
async + await |
| 执行 | 需要手动调用 .next() |
自动执行 |
| 返回值 | Iterator | Promise |
| 语义 | 不够直观 | 更清晰 |
2)async/await 的底层实现
async/await 本质上是:
Generator + 自动执行器 + Promise
可以简单理解为:
function asyncToGenerator(generatorFunc) {
return function() {
const gen = generatorFunc.apply(this, arguments)
return new Promise((resolve, reject) => {
function step(key, arg) {
let result
try {
result = gen[key](arg)
} catch (error) {
return reject(error)
}
const { value, done } = result
if (done) {
return resolve(value)
} else {
return Promise.resolve(value).then(
val => step('next', val),
err => step('throw', err)
)
}
}
step('next')
})
}
}
面试加分说法
async/await可以理解为"自动执行的 Generator + Promise 包装"。
Generator 需要手动调用.next()推进执行,而async函数会自动执行,并且把结果包装成 Promise。
所以理解 Generator,对理解async/await的底层原理很有帮助。
这句话非常有深度。
六、Generator 的优缺点
主动说优缺点会显得成熟。
优点
1)可暂停、可恢复
适合分段执行的场景。
2)惰性求值
按需计算,节省内存。
3)双向通信
内外可以互相传值。
4)天然支持迭代
返回 Iterator,可配合 for...of 等使用。
缺点
1)语法不够直观
不如 async/await 清晰。
2)需要手动执行
不像 async 函数自动执行。
3)错误处理相对复杂
需要通过 .throw() 或 try...catch 配合。
4)现在更多是底层能力
实际开发中直接用 Generator 的场景越来越少,更多是理解异步原理时用到。
七、面试标准回答
我理解 Generator 是 ES6 引入的一种特殊函数,它最核心的能力是可以暂停执行和恢复执行。
普通函数一旦开始就会一直运行到结束,而 Generator 可以通过yield暂停,把控制权交回给调用方,等调用方再次调用.next()时继续执行。语法上,Generator 用
function*定义,内部用yield暂停。调用 Generator 函数不会立即执行,而是返回一个遍历器对象(Iterator),每次调用.next()才会执行到下一个yield。
它有几个核心特性:
第一,可暂停、可恢复,适合分段执行的场景;
第二,yield可以向外传值,.next()也可以向内传值,形成双向通信;
第三,返回的是 Iterator,天然支持for...of等迭代操作;
第四,yield*可以委托给另一个 Generator。使用场景方面,我觉得主要有几个:
第一是异步流程控制,这是 Generator 最早被广泛使用的场景,通过 Generator + co 库可以让异步代码写得像同步一样,这也是async/await的前身;
第二是惰性求值和无限序列,比如斐波那契数列,Generator 可以按需计算,不需要一次性生成所有值;
第三是状态机,Generator 的暂停恢复特性天然适合实现状态切换;
第四是遍历复杂数据结构,比如树的遍历;
第五是实现自定义迭代器。和
async/await的关系上,async/await本质上是 Generator + 自动执行器 + Promise 的语法糖。Generator 需要手动调用.next()推进执行,而async函数会自动执行并返回 Promise。所以理解 Generator,对理解async/await的底层原理很有帮助。总体上,我觉得 Generator 在现代开发中更多是一种底层能力,实际业务代码里直接用的场景不多,更多是用
async/await。但它在理解异步原理、实现惰性求值、状态机等场景下依然很有价值。
八、精简版面试回答
Generator 是 ES6 的一种特殊函数,核心能力是可以暂停执行和恢复执行。
用function*定义,内部用yield暂停,调用后返回 Iterator,每次.next()执行到下一个yield。
它的特点是可暂停恢复、支持双向通信、天然可迭代、支持惰性求值。
主要使用场景有异步流程控制(async/await的前身)、惰性求值(无限序列)、状态机、遍历复杂结构等。async/await本质上是 Generator + 自动执行器 + Promise 的语法糖,所以理解 Generator 有助于理解异步原理。
现在实际开发中更多直接用async/await,但 Generator 在理解底层原理和特定场景下依然有价值。
九、如果想答得更高级,可以补这几句
1)Generator 的本质是协程
Generator 可以理解为 JavaScript 中的"协程"(Coroutine)实现。
协程是一种比线程更轻量的并发单元,可以在执行过程中主动让出控制权,等待被重新唤醒。
Generator 的yield就是让出控制权,.next()就是唤醒。
2)Generator 和 Iterator 的关系
Generator 函数返回的对象,本身就是一个 Iterator。
所以 Generator 是实现自定义迭代器最简单的方式。
3)为什么现在用得少了?
Generator 在异步场景下的价值,主要是历史意义。
async/await出现后,语法更直观、自动执行、错误处理更方便,所以现在异步场景基本都用async/await。
但 Generator 在惰性求值、状态机、自定义迭代器等场景下依然有独特价值。
十、一句话总结
面试官真正想听的是:
- 你是否知道 Generator 的语法和执行机制
- 你能不能说清楚 可暂停恢复、双向通信 这些核心特性
- 你是否理解 Generator 和 async/await 的关系
- 你能不能结合 异步控制、惰性求值、状态机 等实际场景来讲
- 你有没有意识到 Generator 更多是底层能力,现在直接用得少了
更多推荐



所有评论(0)