JavaScript的迭代器和生成器为开发者提供了更灵活的数据遍历和流程控制能力,除了基础的数组遍历、简单数据生成之外,它们在很多复杂场景下都能发挥重要作用,有效简化代码逻辑,提升代码的可维护性。

一、自定义可迭代数据结构的实现
当我们需要定义自己的数据结构,并且希望它支持for...of遍历时,就可以通过实现迭代器协议来完成。比如实现一个支持按斐波那契数列生成数据的自定义结构:
// 自定义斐波那契数列可迭代对象
class FibonacciSequence {
constructor(maxCount) {
this.maxCount = maxCount;
}
[Symbol.iterator]() {
let count = 0;
let prev = 0;
let curr = 1;
return {
next: () => {
if (count >= this.maxCount) {
return { done: true, value: undefined };
}
const value = curr;
const nextPrev = curr;
curr = prev + curr;
prev = nextPrev;
count++;
return { done: false, value };
}
};
}
}
// 使用自定义可迭代对象
const fib = new FibonacciSequence(5);
for (const num of fib) {
console.log(num); // 输出1,1,2,3,5
}
二、生成器实现异步任务调度
在异步编程场景中,生成器可以配合执行器实现类似async/await的效果,尤其适合需要按顺序执行多个异步任务,且任务之间需要等待的场景。下面是一个简单的任务调度器实现:
// 模拟异步请求函数
function fetchData(url) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`从${url}获取数据成功`);
}, 1000);
});
}
// 生成器函数定义异步任务流程
function* asyncTaskGenerator() {
const result1 = yield fetchData('ipipp.com/api/user');
console.log(result1);
const result2 = yield fetchData('ipipp.com/api/order');
console.log(result2);
return '所有任务执行完成';
}
// 生成器执行器
function runGenerator(gen) {
const iterator = gen();
function handle(result) {
if (result.done) {
return result.value;
}
result.value.then(data => {
handle(iterator.next(data));
});
}
handle(iterator.next());
}
runGenerator(asyncTaskGenerator);
三、大数据流的分块处理
当处理大量数据,比如读取大文件或者处理海量接口返回数据时,一次性加载所有数据会占用大量内存,这时候可以用生成器实现分块处理,每次只处理一部分数据:
// 模拟大数据集
const bigData = Array.from({ length: 10000 }, (_, i) => i + 1);
// 分块生成器,每次生成100条数据
function* chunkGenerator(data, chunkSize) {
for (let i = 0; i < data.length; i += chunkSize) {
yield data.slice(i, i + chunkSize);
}
}
// 使用生成器处理分块数据
const chunkSize = 100;
for (const chunk of chunkGenerator(bigData, chunkSize)) {
// 处理当前分块数据,比如发送到后端
console.log(`处理${chunk.length}条数据`);
}
四、生成器实现状态机
状态机是很多业务场景下的常见需求,比如订单状态流转、游戏角色状态切换等,用生成器实现状态机可以让状态流转的逻辑更清晰,代码更易读:
// 订单状态机生成器
function* orderStateMachine() {
let state = '待支付';
while (true) {
const action = yield state;
switch (state) {
case '待支付':
if (action === '支付') {
state = '已支付';
}
break;
case '已支付':
if (action === '发货') {
state = '已发货';
}
break;
case '已发货':
if (action === '确认收货') {
state = '已完成';
}
break;
default:
break;
}
}
}
// 使用状态机
const orderMachine = orderStateMachine();
console.log(orderMachine.next().value); // 待支付
console.log(orderMachine.next('支付').value); // 已支付
console.log(orderMachine.next('发货').value); // 已发货
console.log(orderMachine.next('确认收货').value); // 已完成
五、迭代器实现惰性求值
惰性求值指的是只有在需要数据的时候才去计算生成,而不是提前把所有数据都计算好,这样可以节省内存和计算资源。通过迭代器可以轻松实现惰性求值:
// 惰性生成自然数平方的迭代器
function createLazySquareIterator(max) {
let num = 1;
return {
next: () => {
if (num > max) {
return { done: true, value: undefined };
}
const value = num * num;
num++;
return { done: false, value };
},
[Symbol.iterator]() {
return this;
}
};
}
const lazySquares = createLazySquareIterator(5);
for (const square of lazySquares) {
console.log(square); // 输出1,4,9,16,25,每次遍历时才计算当前值
}
六、总结
迭代器和生成器的高级应用场景远不止以上几种,在实际开发中还可以结合更多业务需求灵活运用。迭代器的核心优势是可以自定义遍历逻辑,让任何对象都支持标准的遍历方式;生成器的核心优势是可以暂停和恢复执行,简化异步流程和复杂状态的管理。掌握这些高级用法,能帮助你写出更优雅、更高效的JavaScript代码。