ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

es-toolkit `iterate` 完全指南:用种子值生成无限惰性迭代器

2026/9/17 2:55:24 拓冰建站 浏览量
es-toolkit `iterate` 完全指南:用种子值生成无限惰性迭代器 es-toolkititerate完全指南用种子值生成无限惰性迭代器【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit导读iterate是 es-toolkit 的es-toolkit/iterator模块提供的核心函数它接收一个种子值seed和一个递推函数反复把当前值变换为下一个值从而构造出无限且惰性求值的迭代器。本文以 docs/ja/iterator/reference/iterate.md 为骨架结合 src/iterator/iterate.ts 的源码与 src/iterator/iterate.spec.ts 的测试讲解iterate的签名、惰性语义、与原生迭代器助手take、toArray等以及takeWhile的组合用法并覆盖 2 的幂、指数退避重试等待时间等真实场景。读完本文你将能够在内存占用恒定的前提下安全地消费无限序列。一、函数签名与基本用法1.1 签名const sequence iterate(seed, getNext);完整签名如下见 src/iterator/iterate.tsexport function iterateT(seed: T, getNext: (value: T) T): IteratorObjectT, undefined参数参数类型说明seedT序列的第一个值getNext(value: T) T从当前值计算下一个值的递推函数返回值IteratorObjectT, undefined覆盖生成序列的无限惰性迭代器。它携带全部原生迭代器助手方法map、filter、take、drop、flatMap、reduce、toArray等可以直接继续链式调用详见第三节。1.2 生成规则iterate生成的值序列为seed, getNext(seed), getNext(getNext(seed)), ...即第 n 个值由getNext应用 n 次得到。例如import { iterate } from es-toolkit/iterator; iterate(1, x x * 2); // 生成 1, 2, 4, 8, 16, 32, ...二、源码解读iterate如何实现惰性与无限iterate的实现非常精简src/iterator/iterate.tsexport function iterateT(seed: T, getNext: (value: T) T): IteratorObjectT, undefined { let current seed; let started false; return iterator(function () { if (started) { current getNext(current); } else { started true; } return { value: current, done: false }; }); }关键点started标志保证第一次调用next()时直接返回seed本身之后每调用一次next()才执行一次getNext(current)更新current。这确保了序列从seed开始的语义测试 src/iterator/iterate.spec.ts 中iterate(42, x x 1).take(1).toArray()返回[42]验证了这一点。永不返回done: truenext始终返回{ value: current, done: false }因此该迭代器在概念上是无限的。它必须由take、takeWhile这类短路助手限定范围后才能消费否则toArray()或for...of会无限循环。惰性求值来自底层 src/iterator/_internal/iterator.tsiterator()用Object.create(Iterator.prototype)包装一个手写的next函数使其行为与原生迭代器助手返回的值完全一致一次性、可被Symbol.iterator迭代、携带全部原生方法。源码注释指出手写next而非使用生成器函数是刻意的性能选择——直接驱动迭代器协议在同类变换下比yield生成器快约 2 倍。惰性语义的测试证据src/iterator/iterate.spec.ts 中的测试用vi.fn间谍验证const next vi.fn((x: number) x 1); iterate(0, next); // 只创建不消费 expect(next).not.toHaveBeenCalled(); // getNext 一次都没有被调用而消费 3 个值.take(3).toArray()时getNext恰好被调用 2 次seed 2 次递推产生 3 个值见 src/iterator/iterate.spec.ts。这印证了文档中的核心承诺迭代器被消费之前不执行任何计算getNext只运行被取出值的次数。三、与原生迭代器助手链式使用iterate返回的IteratorObject以原生Iterator.prototype为原型src/iterator/_internal/iterator.ts因此可以直接调用map、filter、take、drop、flatMap、reduce、toArray等原生助手方法无需额外导入import { iterate } from es-toolkit/iterator; // 2 的幂用 take 限定个数 iterate(1, x x * 2) .take(5) .toArray(); // 结果: [1, 2, 4, 8, 16]也可以先map变换再takeiterate(1, x x * 2) .map(x x - 1) // 0, 1, 3, 7, ... .take(4) .toArray(); // 结果: [0, 1, 3, 7]四、用takeWhile以条件限定无限序列原生助手只有按个数取数的take没有按条件取数的takeWhile因此 es-toolkit 在es-toolkit/iterator中补充了takeWhile。它可以安全地按条件切分无限迭代器shouldContinue返回真值期间持续产出元素遇到第一个返回假值的元素立即停止该元素不包含且剩余元素不再从源迭代器取出。import { iterate } from es-toolkit/iterator; import { takeWhile } from es-toolkit/iterator; takeWhile( iterate(100, x x * 2), x x 60000 ).toArray(); // 结果: [100, 200, 400, ..., 51200]实战场景指数退避的等待时间文档中给出的经典用法是生成 1 分钟以内的指数退避等待时间——重试逻辑中每次失败后等待时间翻倍import { iterate } from es-toolkit/iterator; import { takeWhile } from es-toolkit/iterator; // 1 分钟60000 ms以内的指数退避延迟 const backoffDelays takeWhile( iterate(100, x x * 2), x x 60000 ).toArray(); // [100, 200, 400, 800, 1600, 3200, 6400, 12800, 25600, 51200]同理可以生成连续日期每次加一天或任意递推序列。由于惰性求值即便序列在概念上无限内存占用也恒定在 O(1)仅保存current只有被消费的部分才会真正计算。takeWhile的实现要点takeWhile的源码src/iterator/takeWhile.ts体现了与原生助手一致的迭代器关闭协议当条件不满足提前结束时通过onClose回调调用source.return?.()关闭上游迭代器从而保证生成器源中try/finally的清理逻辑如关闭文件句柄必然执行。这一点对无限迭代器尤为重要——提前终止时不会留下悬空资源。五、与其他 es-toolkit/iterator 函数配合iterate是es-toolkit/iterator模块的一员导出于 src/iterator/index.ts。该模块的定位是只补充原生迭代器助手缺失的能力——按个数取数的take、drop、map、filter等原生已有es-toolkit 在其上增加条件式takeWhile、dropWhile、有状态scan、count、多源zip、cartesianProduct等操作iterate则负责从种子生成无限序列。典型组合iterate生成无限序列 →dropWhile跳过前缀 →takeWhile/take截断 →toArray物化。由于每个环节都返回IteratorObject整条流水线始终是惰性的。六、与pipe函数式风格配合所有es-toolkit/iterator操作都以柯里化形式在es-toolkit/fp/iterator中提供导出清单见 src/fp/iterator/index.ts。虽然该导出集中没有iterate它本身接受种子递推函数不适合柯里化但takeWhile、take、toArray等截断与物化函数均可与pipe组合import { pipe } from es-toolkit/fp; import { takeWhile, toArray } from es-toolkit/fp/iterator; pipe( iterate(1, x x * 2), // 来自 es-toolkit/iterator takeWhile(x x 100), toArray() ); // 结果: [1, 2, 4, 8, 16, 32, 64]七、使用注意事项必须先截断再消费iterate返回无限迭代器直接调用toArray()、reduce()或for...of会无限循环。任何完整消费前都必须用take按个数或takeWhile按条件限定范围。一次性消费与所有 JavaScript 迭代器相同结果只能消费一次消费完毕后不再产生任何值。若需复用序列请重新调用iterate或先toArray()物化。选择合适模块如果数据已在数组中且需要整体处理使用es-toolkit的数组函数即可当输入规模大、可能无限、流水线可能提前结束或数据本身已是迭代器/生成器时才选用es-toolkit/iterator参见 docs/ja/iterator/intro.md。小结iterate(seed, getNext)以 O(1) 内存生成无限惰性序列seed, getNext(seed), getNext(getNext(seed)), ...。返回值是携带全部原生助手方法的IteratorObject可无缝链式调用take、map、toArray等。无限序列必须由take个数或takeWhile条件限定后才能消费takeWhile会正确关闭上游迭代器。典型应用2 的幂、连续日期、指数退避重试等待时间等递推序列。【免费下载链接】es-toolkitA modern JavaScript utility library thats 2-3 times faster and up to 97% smaller, a major upgrade to lodash.项目地址: https://gitcode.com/GitHub_Trending/es/es-toolkit创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考