理解 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");
    });
  }
}
相关推荐
K仔7 小时前
什么是DOM事件模型
前端
熊猫片沃子7 小时前
新手必避的 Vue 基础坑:从数据绑定到事件处理的常见错误与解决方案
前端·vue.js
Java微观世界7 小时前
static在Java中到底怎么用?5分钟搞懂变量、方法、代码块与内部类
后端·面试
lichenyang4537 小时前
UniApp 实现搜索页逻辑详解
前端
怪可爱的地球人7 小时前
处理“文本搜索和替换” 的工具-RegExp
前端
公众号:重生之成为赛博女保安7 小时前
一款基于selenium的前端验证码绕过爆破工具
前端·selenium·测试工具
漫 漫,8 小时前
Vue2存量项目国际化改造踩坑
前端·javascript·vue.js
喜葵8 小时前
前端测试深度实践:从单元测试到E2E测试的完整测试解决方案
前端·单元测试
web前端1238 小时前
React 状态管理方案对比分析
前端