理解 JavaScript 中的 Iterator、Generator、Promise 与 async/await

Iterator 迭代器

在 JavaScript 中,数组、字符串、Map、Set 等都是可迭代对象。但如果你想要遍历一个自定义的数据结构(比如链表、树),没有内置遍历机制该怎么办?

这就是 迭代器模式 出现的原因 ------ 提供统一的访问接口,让不同的数据结构都可以被 for...of 遍历。

工作原理

  1. 创建一个指针对象,指向当前数据结构的起始位置
  2. 第一次调用next()方法,指针自动指向数据结构的第一个成员
  3. 每次调用next(),指针就往后移动
  4. 每次next(),返回一个对象{value,done}
    • value:当前成员值
    • done:是否遍历完成
js 复制代码
const arr = [10, 20, 30];
const it = arr[Symbol.iterator]();

console.log(it.next()); // { value: 10, done: false }
console.log(it.next()); // { value: 20, done: false }
console.log(it.next()); // { value: 30, done: false }
console.log(it.next()); // { value: undefined, done: true }

本质

  • 把遍历逻辑抽象成一个接口
  • 内部维护当前位置,每次调用next()更新状态

手写迭代器

js 复制代码
function createIterator(arr) {
  let index = 0;
  return {
    next() {
      if (index < arr.length) {
        return { value: arr[index++], done: false };
      } else {
        return { value: undefined, done: true };
      }
    }
  };
}

const it = createIterator([1, 2, 3]);
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

Generator 生成器

Generator 是 特殊的函数 ,用 function* 定义,执行时可以被"暂停"和"恢复"。

工作原理

  • 调用function*定义的函数,不会立即执行,而是返回一个迭代器对象
  • 调用next(),函数执行到yeild暂停,并返回对应的值
  • 下次执行next(),会接着上次暂停处继续
  • 可以通过next(value)把值传回函数内部
  • 直到函数结束,返回{value:undefined,done:true}
js 复制代码
function* gen() {
  yield 1;
  yield 2;
  yield 3;
}
const it = gen();

console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: undefined, done: true }

本质

  • 是迭代协议的语法糖
  • 内部是一个状态机,能在不同状态间来回切换
  • 支持协程风格的异步编程(后来async/await取代了它)

Promise

为什么需要Promise?

  • 解决回调地狱
  • 提供统一的异步 API (then/catch/finally)
  • 可链式调用,错误统一处理

工作原理

  • 创建时立即执行 executor(resolve, reject)
  • 内部维护三种状态
    • pending
    • fulfilled
    • rejected
  • 状态发生变化就不可逆
  • 调用then/catch方法,回调会放入微任务队列,在事件循环末端执行
js 复制代码
const p = new Promise((resolve, reject) => {
  setTimeout(() => resolve("ok"), 1000);
});

p.then(res => console.log(res)); // 1秒后打印 "ok"

本质

  • 状态机 + 异步任务调度器

  • 把异步结果抽象成一个"可组合的值";

  • 避免了传统回调地狱。

async/await

为什么需要async/await?

  • Promise 链虽然解决了回调地狱,但可读性仍差
  • async/await 可以写出 同步风格异步代码
  • 错误处理更简单(try/catch)

工作原理

  • async function调用后,始终返回一个Promise
  • 执行遇到await时
    • 表达式立即执行
    • 如果是普通值,转成 Promise.resolve(value)
    • 如果是promise,暂停函数执行,等待结果
  • 等 Promise 完成后,恢复执行,并把结果返回给 await 表达式
  • 如果Promise失败,抛出错误,可以使用try...catch捕获
js 复制代码
async function getData() {
  const res = await new Promise(resolve => setTimeout(() => resolve("ok"), 1000));
  console.log(res); // "ok"
}
getData();

本质

  • Generator + Promise 的语法糖
  • Babel 转译 async/await → Generator
  • 让异步代码看起来像同步,更易读易维护

babel转译原理

js 复制代码
async function fetchData() {
  const a = await getA();
  const b = await getB(a);
  return b;
}

// 转译等价于
function fetchData() {
  return _asyncToGenerator(function* () {
    const a = yield getA();
    const b = yield getB(a);
    return b;
  })();
}

function _asyncToGenerator(genFn) {
  return function() {
    const gen = genFn.apply(this, arguments);
    return new Promise((resolve, reject) => {
      function step(key, arg) {
        let info;
        try { info = gen[key](arg); } 
        catch (err) { return reject(err); }
        if (info.done) resolve(info.value);
        else Promise.resolve(info.value)
          .then(val => step("next", val), err => step("throw", err));
      }
      step("next");
    });
  }
}
相关推荐
很晚很晚了4 小时前
纯前端转全栈 Day 1:我从第一个 NestJS 接口开始
前端
Lee川5 小时前
从零解剖一个 AI Agent Tool是如何实现的
前端·人工智能·后端
wangruofeng6 小时前
Playwright 深度调研:为什么它成了浏览器自动化的新底座
前端·测试
程序员雷欧6 小时前
大厂计算机网络面试高频题
计算机网络·面试·职场和发展
李白的天不白8 小时前
SSR服务端渲染
前端
卷帘依旧9 小时前
SSE(Server-Sent Events)完全指南
前端
码云之上9 小时前
万星入坞:我们如何用三层插件体系干掉巨石应用
前端·架构·前端框架
kyriewen9 小时前
一口气讲清楚 Monorepo、Turborepo、pnpm、Changesets 到底是什么?
前端·架构·前端工程化
JAVA学习通9 小时前
美团AI面试 实习一面面经
面试·职场和发展
卷帘依旧10 小时前
怎么保证AI生成的代码是符合预期的
面试