🌟ES6迭代器与生成器终极指南:掌控异步编程核心🔑(附原理剖析)
🎯 博主说:本文包含28个核心知识点+6大实战场景+底层源码解析,带你从入门到实现自定义迭代协议!文末赠【手写迭代器源码】💻
一、💡 为什么需要迭代器?先看痛点场景
1.1 传统遍历的局限 😫
const arr = [1,2,3];
let index = 0;
// 方式1:for循环
for(let i=0; i<arr.length; i++){...}
// 方式2:forEach
arr.forEach(v => {...})
// 痛点:
// 1. 无法统一遍历所有数据结构
// 2. 无法中断循环
// 3. 不支持异步遍历
1.2 迭代器三大革命性特性 🔥
- 统一访问接口:任何数据结构只要实现迭代协议
- 懒加载机制:按需生成值,节省内存
- 异步支持:完美配合Generator处理异步
二、🚀 迭代器深度解析:从协议到底层
2.1 迭代协议三要素 📚
const myIterable = {
[Symbol.iterator]() {
let count = 0;
return {
next() {
return count < 3
? { value: count++, done: false }
: { value: undefined, done: true };
}
};
}
};
// ✅ 符合迭代协议
for(const num of myIterable) {
console.log(num); // 0,1,2
}
2.2 原生可迭代对象 🏷️
对象类型 | 示例 | 迭代内容 |
---|---|---|
Array | [1,2,3] | 元素值 |
String | ‘hello’ | 字符 |
Map | new Map() | [key, value]对 |
NodeList | document.querySelectorAll() | DOM节点 |
2.3 手写迭代器实战 🛠️
场景:实现范围数字迭代
class Range {
constructor(start, end) {
this.start = start;
this.end = end;
}
[Symbol.iterator]() {
let current = this.start;
return {
next: () => {
return current <= this.end
? { value: current++, done: false }
: { done: true };
}
};
}
}
// 使用
for(const num of new Range(5, 7)) {
console.log(num); // 5,6,7
}
三、💎 Generator高阶应用:超越异步编程
3.1 生成器核心语法 ✨
function* genDemo() {
yield 'Hello';
yield 'Generator';
return 'End';
}
const gen = genDemo();
console.log(gen.next()); // {value: 'Hello', done: false}
console.log(gen.next()); // {value: 'Generator', done: false}
console.log(gen.next()); // {value: 'End', done: true}
3.2 生成器执行原理 🔍
- 遇到yield暂停执行
- 保留当前执行上下文
- next()触发恢复执行
- 通过yield实现双向通信
3.3 六大实战场景 🎩
场景1:无限数据流
function* fibonacci() {
let [prev, curr] = [0, 1];
while(true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
const fib = fibonacci();
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
场景2:异步流程控制
function* asyncFlow() {
const user = yield fetchUser();
const posts = yield fetchPosts(user.id);
yield saveData(posts);
}
function run(generator) {
const gen = generator();
function handle(result) {
if(result.done) return;
result.value.then(data => {
handle(gen.next(data));
});
}
handle(gen.next());
}
run(asyncFlow); // 类似co库实现
四、⚡ 性能优化与最佳实践
4.1 迭代器内存管理 🧠
// 错误示例:大数据导致内存溢出
function* bigArray() {
const arr = new Array(1e6).fill(0);
for(const item of arr) {
yield item;
}
}
// 正确方案:按需生成
function* smartGenerator() {
let count = 0;
while(count < 1e6) {
yield count++;
}
}
4.2 生成器委托模式 ✈️
function* genA() {
yield 'A1';
yield 'A2';
}
function* genB() {
yield* genA(); // 委托执行
yield 'B1';
}
const it = genB();
console.log([...it]); // ['A1', 'A2', 'B1']
4.3 三大进阶技巧 🔥
- 错误处理:
function* errorHandling() {
try {
yield 'Normal';
throw new Error('Generator error');
} catch(e) {
console.log('Caught:', e.message);
}
}
- 双向通信:
function* twoWay() {
const name = yield 'Please input name:';
yield `Hello ${name}!`;
}
const gen = twoWay();
console.log(gen.next().value); // Please input name:
console.log(gen.next('Alice').value); // Hello Alice!
- 状态机实现:
function* stateMachine() {
let state = 'start';
while(true) {
const input = yield state;
state = input === 'next'
? 'running'
: input === 'stop'
? 'end'
: state;
}
}
五、📌 高频面试题精选
Q1:for…of循环如何工作?
💡 深度解析:
- 调用对象的
Symbol.iterator
方法获取迭代器 - 重复调用迭代器的
next()
方法 - 直到遇到
done: true
停止 - 内部自动处理错误和关闭
Q2:实现异步自动执行器
function asyncRunner(generator) {
const gen = generator();
function step(nextF) {
try {
const { value, done } = nextF();
if(done) return;
if(value instanceof Promise) {
value.then(
v => step(() => gen.next(v)),
e => step(() => gen.throw(e))
);
} else {
step(() => gen.next(value));
}
} catch(e) {
gen.throw(e);
}
}
step(() => gen.next());
}
六、🌈 总结 & 技术选型
🚦 使用场景决策树
是否需要懒加载数据?
→ 是 → 使用Generator
→ 否 → 是否需要统一遍历接口?
→ 是 → 实现迭代协议
→ 否 → 普通循环即可
🔮 生态应用
- Redux-Saga的核心机制
- Koa的中间件控制流
- Babel的代码转换
- React Suspense的异步加载
🌟 资源推荐:
📢 互动话题:你在项目中用过哪些迭代器/生成器的骚操作?评论区等你来秀!🚀