ES6生成器函数详解
ES6引入的生成器函数(Generator Function)是一种特殊的函数,允许通过yield
关键字暂停和恢复执行流程。生成器函数在定义时使用function*
语法,调用时返回一个生成器对象(Generator Object),而非直接执行函数体。
生成器对象遵循迭代器协议(Iterator Protocol),可通过next()
方法逐步执行代码,每次遇到yield
时暂停,并返回一个包含value
和done
属性的对象。value
为yield
后的表达式值,done
表示生成器是否执行完毕。
语法特性
-
定义方式
使用
function*
声明生成器函数:javascriptfunction* generatorFunc() { yield 1; yield 2; return 3; }
-
yield
关键字
yield
用于暂停函数执行并返回一个值,后续调用next()
时从暂停处继续执行。 -
迭代器协议
生成器函数返回的迭代器对象符合迭代器协议,包含
next()
、return()
和throw()
方法。 -
yield*
委托用于委托给另一个生成器或可迭代对象:
javascriptfunction* generatorA() { yield 1; } function* generatorB() { yield* generatorA(); }
应用场景
-
惰性求值生成器适合处理大数据集或无限序列,仅在需要时计算值。例如生成斐波那契数列:
javascriptfunction* fibonacci() { let [a, b] = [0, 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
-
异步流程控制 生成器可用于简化异步代码,结合
yield
暂停特性,实现类似同步的异步操作写法。例如:javascriptfunction* fetchUser() { const response = yield fetch('https://api.example.com/user'); const data = yield response.json(); return data; } const generator = fetchUser(); const promise = generator.next().value; promise.then(response => { return generator.next(response).value; }).then(data => { console.log(generator.next(data).value); });
-
状态机
生成器天然适合实现状态机逻辑,每个
yield
代表一个状态节点:javascriptfunction* trafficLight() { while (true) { yield 'red'; yield 'yellow'; yield 'green'; } } const light = trafficLight(); light.next().value; // 'red' light.next().value; // 'yellow'
注意事项
- 执行顺序 :生成器函数在首次调用
next()
时才开始执行,而非声明时。 - 错误处理 :可通过
generator.throw()
向生成器内部抛出错误,需在函数体内用try/catch
捕获。 - 资源清理 :若提前终止生成器,应调用
generator.return()
释放资源。 - 兼容性:旧版浏览器需通过Babel等工具转译。
优化建议
-
避免频繁创建:对性能敏感场景,复用生成器对象而非重复创建。
-
结合
for...of
:遍历生成器时使用for...of
语法更简洁:javascriptfor (const value of fibonacci()) { if (value > 100) break; console.log(value); }
-
与
Promise
配合 :使用库如co
或异步生成器(ES2018)进一步简化异步代码:javascriptasync function* asyncGenerator() { yield await Promise.resolve(1); }
总结
生成器函数提供了一种控制执行流程的灵活机制,适用于异步编程、惰性计算和状态管理等场景。尽管现代JavaScript已引入async/await
处理异步操作,生成器仍在特定场景下具有独特优势。合理使用生成器能提升代码可读性和维护性,但需注意其执行特性和性能开销。