一、迭代器(Iterator):数据遍历的统一协议
1. 迭代器协议的本质
**迭代器协议(Iterator Protocol)** 是一种标准化的数据访问接口,它要求对象实现一个 `next()` 方法,每次调用返回包含 `{ value, done }` 的对象。
- **`value`**: 当前遍历的值
- **`done`**: 布尔值,表示遍历是否结束
const arrayIterator = {
data: [1, 2, 3],
index: 0,
next() {
return this.index < this.data.length
? { value: this.data[this.index++], done: false }
: { value: undefined, done: true };
}
};
console.log(arrayIterator.next()); // { value: 1, done: false }
此迭代器通过内部维护的 `index` 状态,逐步遍历数组元素。
2. 可迭代对象(Iterable)
若对象实现了[Symbol.iterator]() 方法,则称为 可迭代对象。该方法返回一个迭代器,使得对象可被 `for...of` 等语法消费。
自定义可迭代链表:
class LinkedList {
constructor() {
this.nodes = [];
}
add(node) {
this.nodes.push(node);
}
[Symbol.iterator]() {
let index = 0;
return {
next: () => ({
value: this.nodes[index++],
done: index > this.nodes.length
})
};
}
}
const list = new LinkedList();
list.add('a'); list.add('b');
for (const node of list) {
console.log(node); // 'a', 'b'
}
二、生成器(Generator):迭代器的超级语法糖
1. 生成器的核心机制
生成器函数(function*)返回一个 生成器对象,该对象既是迭代器,也是可迭代对象。其核心能力在于:
- 暂停与恢复执行:通过 `yield` 关键字中断函数,保留上下文状态
- 双向通信:`yield` 可向外传递值,外部可通过 `next(arg)` 向内注入值 生成器执行流程
function* gen() {
const a = yield 1;
const b = yield a + 2;
yield b * 3;
}
const g = gen();
console.log(g.next()); // { value: 1, done: false }
console.log(g.next(10)); // { value: 12, done: false } (a = 10)
console.log(g.next(5)); // { value: 15, done: false } (b = 5)
console.log(g.next()); // { value: undefined, done: true }
**关键点**:每次 `next(arg)` 的 `arg` 会赋值给左侧 `yield` 表达式的返回值。
2. 生成器的底层模型
生成器本质是 **协程(Coroutine)** 的轻量级实现。与线程不同,协程的切换由开发者显式控制,且不涉及系统内核,因此极其高效。
- 执行上下文栈:生成器暂停时,其执行上下文(变量、作用域链)被保存,恢复时重新压入栈顶
- 状态机转换:Babel 等工具将生成器转换为带有 `switch-case` 的状态机代码
三、高级应用场景
1. 异步流程控制:生成器的革命性贡献
在 `async/await` 普及前,生成器 + Promise 是处理异步代码的终极方案,其核心模式如下:
实现自动执行器
function run(generator) {
const g = generator();
function handle(result) {
if (result.done) return result.value;
return result.value.then(
data => handle(g.next(data)),
err => handle(g.throw(err))
);
}
return handle(g.next());
}
run(function* fetchUser() {
const user = yield fetch('/api/user');
const posts = yield fetch(`/api/posts?userId=${user.id}`);
return { user, posts };
}).then(data => console.log(data));
此模式直接催生了 `async/await` 的诞生,两者在 Babel 中被编译为类似的生成器代码。
2. 无限数据流与惰性计算
生成器天然适合处理大规模或无限序列,仅在需要时计算值,避免内存爆炸。
斐波那契数列
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
const seq = fibonacci();
console.log(seq.next().value); // 1
console.log(seq.next().value); // 1
console.log(seq.next().value); // 2
// 可无限调用,但每次只计算一个值
3. 复杂状态机
生成器通过 `yield` 管理状态转移,代码比传统状态机更简洁。
交通灯状态机
function* trafficLight() {
while (true) {
yield 'Red'; // 返回 'Red'
yield delay(3000); // 返回 Promise,暂停 3 秒
yield 'Green'; // 返回 'Green'
yield delay(2000); // 返回 Promise,暂停 2 秒
yield 'Yellow'; // 返回 'Yellow'
yield delay(1000); // 返回 Promise,暂停 1 秒
}
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 使用
const light = trafficLight();
function runTrafficLight() {
const { value, done } = light.next();
if (done) return; // 如果生成器结束,退出
if (typeof value === 'string') {
console.log(value); // 更新 UI 为当前颜色
runTrafficLight(); // 继续下一步
} else if (value instanceof Promise) {
value.then(() => runTrafficLight()); // 等待 Promise 完成后再继续
}
}
runTrafficLight(); // 启动交通灯
四、生成器与迭代器的未来
1. 异步迭代器(Async Iterator)
ES2018 引入的异步迭代器,允许迭代异步数据源(如数据库流、WebSocket):
async function* asyncCounter() {
let i = 0;
while (i < 3) {
await sleep(1000);
yield i++;
}
}
(async () => {
for await (const num of asyncCounter()) {
console.log(num); // 0, 1, 2(每秒输出一个)
}
})();