【ES6新特性】生成器&迭代器

发布于:2025-04-05 ⋅ 阅读:(55) ⋅ 点赞:(0)

🌟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 迭代器三大革命性特性 🔥

  1. 统一访问接口:任何数据结构只要实现迭代协议
  2. 懒加载机制:按需生成值,节省内存
  3. 异步支持:完美配合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 生成器执行原理 🔍

  1. 遇到yield暂停执行
  2. 保留当前执行上下文
  3. next()触发恢复执行
  4. 通过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 三大进阶技巧 🔥

  1. 错误处理
function* errorHandling() {
  try {
    yield 'Normal';
    throw new Error('Generator error');
  } catch(e) {
    console.log('Caught:', e.message);
  }
}
  1. 双向通信
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!
  1. 状态机实现
function* stateMachine() {
  let state = 'start';
  while(true) {
    const input = yield state;
    state = input === 'next' 
      ? 'running' 
      : input === 'stop' 
        ? 'end' 
        : state;
  }
}

五、📌 高频面试题精选

Q1:for…of循环如何工作?

💡 深度解析

  1. 调用对象的Symbol.iterator方法获取迭代器
  2. 重复调用迭代器的next()方法
  3. 直到遇到done: true停止
  4. 内部自动处理错误和关闭

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的异步加载

🌟 资源推荐

📢 互动话题:你在项目中用过哪些迭代器/生成器的骚操作?评论区等你来秀!🚀


网站公告

今日签到

点亮在社区的每一天
去签到