还在无脑 .map().filter()?实测改用 Iterator Helpers 后,内存占用降低了 99%
别再把所有东西都转成数组了:Iterator Helpers 性能实测
今天看到一篇文章,标题很直接:Stop turning everything into arrays。作者的观点是,JavaScript 里我们习惯了用 .map().filter().slice() 这种链式调用,看着很优雅,但其实每一步都在创建新数组,做了很多不必要的工作。
我一开始也半信半疑,毕竟这种写法用了这么多年,真的有那么大问题吗?于是我写了个测试脚本,跑了几组对比实验,结果还挺出乎意料的。
问题在哪
先说传统数组方法的问题。假设你有个常见场景:从一个大列表里筛选出符合条件的数据,做点转换,然后只取前 10 条显示。
const visibleItems = items
.filter(item => item.active)
.map(item => ({ id: item.id, doubled: item.value * 2 }))
.slice(0, 10);
这代码看着没毛病,但实际执行时:
-
filter遍历整个数组,创建一个新数组 -
map再遍历一遍,又创建一个新数组 -
slice最后从结果里取前 10 条,又创建一个新数组
如果 items 有 10 万条数据,你可能只需要 10 条,但前面两步已经把 10 万条全处理完了。这就是"急切求值"(eager evaluation)的问题——不管你最后用不用,先把活全干了再说。
Iterator Helpers 是什么
Iterator Helpers 是 JavaScript 新加的特性,提供了一套"惰性求值"(lazy evaluation)的方法。关键区别是:
- 传统数组方法:每一步都立即执行,创建中间数组
- Iterator Helpers:只描述要做什么,真正需要数据时才执行
用法上也很直观:
const visibleItems = items
.values() // 转成 iterator
.filter(item => item.active)
.map(item => ({ id: item.id, doubled: item.value * 2 }))
.take(10) // 只取 10 条
.toArray(); // 最后转回数组
核心差异在于:
-
items.values()返回的是 iterator,不是数组 - 每一步只是在"描述"操作,不会立即执行
-
take(10)告诉它只需要 10 条,处理到 10 条就停 -
toArray()才真正触发执行,而且只处理需要的数据
实测对比
我写了个测试脚本,从时间和空间两个维度进行对比测试。每组场景的时间测试重复 10 次取平均值,内存测试使用 Node.js 的 process.memoryUsage() API 测量堆内存增长。
场景 1:过滤 + 转换 + 取前 10 项
数据规模:100,000 条
// 传统数组方法
dataset
.filter(item => item.active)
.map(item => ({ id: item.id, doubled: item.value * 2 }))
.slice(0, 10);
// Iterator Helpers
dataset
.values()
.filter(item => item.active)
.map(item => ({ id: item.id, doubled: item.value * 2 }))
.take(10)
.toArray();
结果:
| 维度 | 传统数组方法 | Iterator Helpers | 性能提升 |
|---|---|---|---|
| 时间 | 1.545ms | 0.019ms | 98.77% |
| 内存 | 3.38 MB | 0.01 MB | 99.75% |
这个结果很夸张,Iterator Helpers 在时间上快了 80 多倍,内存使用更是只有传统方法的 0.3%。原因很简单:传统方法处理了所有 10 万条数据并创建了 2 个中间数组(filter 和 map 各一个),而 Iterator Helpers 找到 10 条就停了,完全不创建中间数组。
场景 2:嵌套数据扁平化
数据规模:10,000 个父项,每个包含 10 个子项(共 100,000 条子数据)
// 传统数组方法
dataset
.flatMap(parent => parent.children)
.filter(child => child.value > 50)
.slice(0, 20);
// Iterator Helpers
dataset
.values()
.flatMap(parent => parent.children)
.filter(child => child.value > 50)
.take(20)
.toArray();
结果:
| 维度 | 传统数组方法 | Iterator Helpers | 性能提升 |
|---|---|---|---|
| 时间 | 3.716ms | 0.018ms | 99.53% |
| 内存 | 4.03 MB | 0.01 MB | 99.73% |
flatMap 这种场景更明显,因为传统方法要先把所有嵌套数据(10 万条子数据)展平成一个大数组,再过滤,再切片,创建了 2 个中间数组。Iterator Helpers 直接在展平的过程中就能提前终止,内存使用几乎可以忽略不计。
场景 3:查找第一个匹配项
数据规模:1,000,000 条(目标在第 800,000 条)
// 传统数组方法
dataset.filter(item => item.id === targetId)[0];
// Iterator Helpers
dataset.values().find(item => item.id === targetId);
结果:
| 维度 | 传统数组方法 | Iterator Helpers | 性能变化 |
|---|---|---|---|
| 时间 | 6.587ms | 8.713ms | -32.27% ⚠️ |
| 内存 | 0.01 MB | 14.80 MB | -194800% ⚠️ |
这个场景很有意思,Iterator Helpers 在时间和空间上都更差了。我分析了一下原因:
-
时间慢的原因:目标在数据集后半部分(第 80 万条),两者都要遍历大部分数据。
filter是原生实现,优化得很好;而 Iterator Helpers 的find每次迭代的开销更大 - 内存多的原因:这个测试结果有点反直觉,可能是因为 iterator 本身的内部状态占用了内存,而且 GC 时机不同导致测量偏差
这说明 Iterator Helpers 不是银弹,在"需要遍历大部分数据"的场景下,传统方法可能更好。
场景 4:复杂链式调用
数据规模:50,000 条
// 传统数组方法
dataset
.filter(item => item.active)
.map(item => ({ ...item, doubled: item.value * 2 }))
.filter(item => item.doubled > 500)
.map(item => ({ id: item.id, final: item.doubled + 100 }))
.slice(0, 15);
// Iterator Helpers
dataset
.values()
.filter(item => item.active)
.map(item => ({ ...item, doubled: item.value * 2 }))
.filter(item => item.doubled > 500)
.map(item => ({ id: item.id, final: item.doubled + 100 }))
.take(15)
.toArray();
结果:
| 维度 | 传统数组方法 | Iterator Helpers | 性能提升 |
|---|---|---|---|
| 时间 | 1.421ms | 0.028ms | 98.02% |
| 内存 | 5.33 MB | 0.01 MB | 99.75% |
链式调用越多,传统方法创建的中间数组就越多。这个场景有 4 次操作(filter → map → filter → map),传统方法创建了 4 个中间数组,总共占用 5.33 MB 内存;而 Iterator Helpers 一个中间数组都没创建,内存使用几乎为零。
什么时候用 Iterator Helpers
根据测试结果,我总结了几个适合用 Iterator Helpers 的场景:
1. 只需要前 N 项
这是最明显的优势场景。无限滚动、分页加载、虚拟列表这些场景都适合。
// 虚拟列表只渲染可见的 20 条
const visibleRows = allRows
.values()
.filter(isInViewport)
.take(20)
.toArray();
2. 流式数据处理
处理 API 分页、SSE 流、WebSocket 消息这些场景,Iterator Helpers 配合 async iterator 很好用:
async function* fetchPages() {
let page = 1;
while (true) {
const res = await fetch(`/api/items?page=${page++}`);
if (!res.ok) return;
yield* await res.json();
}
}
// 只拉取需要的数据,不会一次性加载所有分页
const firstTen = await fetchPages()
.filter(isValid)
.take(10)
.toArray();
3. 复杂的数据管道
如果你的数据处理链路很长,有多次 filter、map、flatMap,用 Iterator Helpers 能避免创建一堆中间数组。
const result = data
.values()
.filter(step1)
.map(step2)
.flatMap(step3)
.filter(step4)
.take(100)
.toArray();
什么时候不用
Iterator Helpers 也不是万能的,这几种情况还是老老实实用数组:
1. 需要随机访问
Iterator 是单向的,不能 items[5] 这样直接取某一项。如果你需要随机访问,还是得用数组。
2. 数据量很小
如果就几十条数据,用 Iterator Helpers 反而增加了复杂度,传统数组方法更简单直接。
3. 需要多次遍历
Iterator 只能遍历一次,如果你需要对同一份数据做多次不同的处理,还是先 toArray() 转成数组再说。
const iter = data.values().filter(x => x > 10);
// ❌ 第二次遍历会返回空,因为 iterator 已经消费完了
const first = iter.take(5).toArray();
const second = iter.take(5).toArray(); // []
// ✅ 先转数组,再多次使用
const filtered = data.values().filter(x => x > 10).toArray();
const first = filtered.slice(0, 5);
const second = filtered.slice(5, 10);
兼容性
Iterator Helpers 在现代浏览器和 Node.js 22+ 都已经支持了。如果你的项目还要兼容老版本,可以用 core-js 这类 polyfill。
可以在 Can I Use 查看详细的兼容性数据。
一些坑
1. Iterator 不是数组
这是最容易踩的坑。Iterator 没有 length、[index] 这些属性,也不能直接 console.log 看内容。
const iter = [1, 2, 3].values();
console.log(iter.length); // undefined
console.log(iter[0]); // undefined
console.log(iter); // Object [Array Iterator] {}
// 要看内容,得先转数组
console.log([...iter]); // [1, 2, 3]
2. reduce 不是惰性的
大部分 Iterator Helpers 都是惰性的,但 reduce 是个例外,它必须遍历所有数据才能得出结果。
// reduce 会立即消费整个 iterator
const sum = data.values().reduce((acc, x) => acc + x, 0);
3. 调试不方便
因为是惰性求值,你不能在中间步骤打断点看数据。如果要调试,可以在关键步骤插入 toArray() 转成数组再看。
const result = data
.values()
.filter(step1)
.toArray() // 调试用,看看 filter 后的结果
.values()
.map(step2)
.take(10)
.toArray();
总结
Iterator Helpers 不是要替代数组,而是给了我们另一个选择。核心思路就一句话:如果你不需要整个数组,就别创建它。
从实测结果看:
- 在"取前 N 项"这类场景下,时间和空间开销都能降低 90%+
- 在"需要遍历大部分数据"的场景下,传统方法可能更快(场景 3 是个反例)
- 数据规模越大,Iterator Helpers 的优势越明显
- 内存优势尤其突出:传统方法创建的中间数组会占用大量内存,而 Iterator Helpers 几乎不占用额外内存
我个人的使用建议是:
- 默认还是用数组方法,简单直接,不容易出错
- 遇到性能瓶颈时,看看是不是"只需要部分数据却处理了全部",如果是,试试 Iterator Helpers
- 写数据管道时,如果链路很长,用 Iterator Helpers 能让代码更清晰,也能避免不必要的内存分配
- 内存敏感场景,比如处理大数据集、移动端应用等,Iterator Helpers 能显著降低内存压力
完整测试代码
下面是完整的性能测试代码,包含时间和空间两个维度的测试。你可以复制到本地跑一下:
/**
* Iterator Helpers vs Array Methods 性能对比测试
*
* 测试维度:
* 1. 时间开销(执行时间)
* 2. 空间开销(内存使用)
*
* 测试场景:
* 1. 大数据集过滤 + 转换 + 取前 N 项
* 2. 嵌套数据扁平化
* 3. 查找第一个匹配项
* 4. 复杂链式调用
*/
// ============ 工具函数 ============
function generateLargeDataset(size) {
return Array.from({ length: size }, (_, i) => ({
id: i,
value: Math.random() * 1000,
category: ['A', 'B', 'C', 'D'][i % 4],
active: i % 3 === 0
}));
}
function benchmark(name, fn, iterations = 1) {
const times = [];
for (let i = 0; i < iterations; i++) {
const start = performance.now();
fn();
const end = performance.now();
times.push(end - start);
}
const avg = times.reduce((a, b) => a + b, 0) / times.length;
const min = Math.min(...times);
const max = Math.max(...times);
console.log(`\n${name}:`);
console.log(` 平均: ${avg.toFixed(3)}ms`);
console.log(` 最小: ${min.toFixed(3)}ms`);
console.log(` 最大: ${max.toFixed(3)}ms`);
return avg;
}
function memoryBenchmark(name, fn) {
// 强制垃圾回收(需要 Node.js 启动时加 --expose-gc 参数)
if (global.gc) {
global.gc();
}
const memBefore = process.memoryUsage();
fn();
const memAfter = process.memoryUsage();
const heapUsedDiff = (memAfter.heapUsed - memBefore.heapUsed) / 1024 / 1024;
console.log(` 内存增长: ${heapUsedDiff.toFixed(2)} MB`);
return heapUsedDiff;
}
// ============ 测试场景 1: 过滤 + 转换 + 取前 N 项 ============
console.log('='.repeat(60));
console.log('测试场景 1: 大数据集过滤 + 转换 + 取前 10 项');
console.log('数据规模: 100,000 条');
console.log('='.repeat(60));
const dataset1 = generateLargeDataset(100000);
// 传统数组方法 - 时间
const arrayMethodTime1 = benchmark('传统数组方法 (filter + map + slice) - 时间', () => {
const result = dataset1
.filter(item => item.active)
.map(item => ({ id: item.id, doubled: item.value * 2 }))
.slice(0, 10);
return result;
}, 10);
// 传统数组方法 - 内存
const arrayMethodMem1 = memoryBenchmark('传统数组方法 (filter + map + slice) - 内存', () => {
const result = dataset1
.filter(item => item.active)
.map(item => ({ id: item.id, doubled: item.value * 2 }))
.slice(0, 10);
return result;
});
// Iterator Helpers - 时间
const iteratorHelpersTime1 = benchmark('Iterator Helpers (filter + map + take) - 时间', () => {
const result = dataset1
.values()
.filter(item => item.active)
.map(item => ({ id: item.id, doubled: item.value * 2 }))
.take(10)
.toArray();
return result;
}, 10);
// Iterator Helpers - 内存
const iteratorHelpersMem1 = memoryBenchmark('Iterator Helpers (filter + map + take) - 内存', () => {
const result = dataset1
.values()
.filter(item => item.active)
.map(item => ({ id: item.id, doubled: item.value * 2 }))
.take(10)
.toArray();
return result;
});
const timeImprovement1 = ((arrayMethodTime1 - iteratorHelpersTime1) / arrayMethodTime1 * 100).toFixed(2);
const memImprovement1 = ((arrayMethodMem1 - iteratorHelpersMem1) / arrayMethodMem1 * 100).toFixed(2);
console.log(`\n性能提升: 时间 ${timeImprovement1}%, 内存 ${memImprovement1}%`);
// ============ 测试场景 2: 嵌套数据扁平化 ============
console.log('\n' + '='.repeat(60));
console.log('测试场景 2: 嵌套数据扁平化 + 过滤 + 取前 20 项');
console.log('数据规模: 10,000 个父项,每个包含 10 个子项');
console.log('='.repeat(60));
const dataset2 = Array.from({ length: 10000 }, (_, i) => ({
id: i,
children: Array.from({ length: 10 }, (_, j) => ({
childId: `${i}-${j}`,
value: Math.random() * 100
}))
}));
// 传统数组方法 - 时间
const arrayMethodTime2 = benchmark('传统数组方法 (flatMap + filter + slice) - 时间', () => {
const result = dataset2
.flatMap(parent => parent.children)
.filter(child => child.value > 50)
.slice(0, 20);
return result;
}, 10);
// 传统数组方法 - 内存
const arrayMethodMem2 = memoryBenchmark('传统数组方法 (flatMap + filter + slice) - 内存', () => {
const result = dataset2
.flatMap(parent => parent.children)
.filter(child => child.value > 50)
.slice(0, 20);
return result;
});
// Iterator Helpers - 时间
const iteratorHelpersTime2 = benchmark('Iterator Helpers (flatMap + filter + take) - 时间', () => {
const result = dataset2
.values()
.flatMap(parent => parent.children)
.filter(child => child.value > 50)
.take(20)
.toArray();
return result;
}, 10);
// Iterator Helpers - 内存
const iteratorHelpersMem2 = memoryBenchmark('Iterator Helpers (flatMap + filter + take) - 内存', () => {
const result = dataset2
.values()
.flatMap(parent => parent.children)
.filter(child => child.value > 50)
.take(20)
.toArray();
return result;
});
const timeImprovement2 = ((arrayMethodTime2 - iteratorHelpersTime2) / arrayMethodTime2 * 100).toFixed(2);
const memImprovement2 = ((arrayMethodMem2 - iteratorHelpersMem2) / arrayMethodMem2 * 100).toFixed(2);
console.log(`\n性能提升: 时间 ${timeImprovement2}%, 内存 ${memImprovement2}%`);
// ============ 测试场景 3: 查找第一个匹配项 ============
console.log('\n' + '='.repeat(60));
console.log('测试场景 3: 查找第一个匹配项(匹配项在数据集后半部分)');
console.log('数据规模: 1,000,000 条');
console.log('='.repeat(60));
const dataset3 = generateLargeDataset(1000000);
const targetId = 800000;
// 传统数组方法 - 时间
const arrayMethodTime3 = benchmark('传统数组方法 (filter + [0]) - 时间', () => {
const result = dataset3
.filter(item => item.id === targetId)[0];
return result;
}, 10);
// 传统数组方法 - 内存
const arrayMethodMem3 = memoryBenchmark('传统数组方法 (filter + [0]) - 内存', () => {
const result = dataset3
.filter(item => item.id === targetId)[0];
return result;
});
// Iterator Helpers - 时间
const iteratorHelpersTime3 = benchmark('Iterator Helpers (find) - 时间', () => {
const result = dataset3
.values()
.find(item => item.id === targetId);
return result;
}, 10);
// Iterator Helpers - 内存
const iteratorHelpersMem3 = memoryBenchmark('Iterator Helpers (find) - 内存', () => {
const result = dataset3
.values()
.find(item => item.id === targetId);
return result;
});
const timeImprovement3 = ((arrayMethodTime3 - iteratorHelpersTime3) / arrayMethodTime3 * 100).toFixed(2);
const memImprovement3 = ((arrayMethodMem3 - iteratorHelpersMem3) / arrayMethodMem3 * 100).toFixed(2);
console.log(`\n性能提升: 时间 ${timeImprovement3}%, 内存 ${memImprovement3}%`);
// ============ 测试场景 4: 多次链式调用 ============
console.log('\n' + '='.repeat(60));
console.log('测试场景 4: 复杂链式调用(filter + map + filter + map + take)');
console.log('数据规模: 50,000 条');
console.log('='.repeat(60));
const dataset4 = generateLargeDataset(50000);
// 传统数组方法 - 时间
const arrayMethodTime4 = benchmark('传统数组方法 (多次链式调用) - 时间', () => {
const result = dataset4
.filter(item => item.active)
.map(item => ({ ...item, doubled: item.value * 2 }))
.filter(item => item.doubled > 500)
.map(item => ({ id: item.id, final: item.doubled + 100 }))
.slice(0, 15);
return result;
}, 10);
// 传统数组方法 - 内存
const arrayMethodMem4 = memoryBenchmark('传统数组方法 (多次链式调用) - 内存', () => {
const result = dataset4
.filter(item => item.active)
.map(item => ({ ...item, doubled: item.value * 2 }))
.filter(item => item.doubled > 500)
.map(item => ({ id: item.id, final: item.doubled + 100 }))
.slice(0, 15);
return result;
});
// Iterator Helpers - 时间
const iteratorHelpersTime4 = benchmark('Iterator Helpers (多次链式调用) - 时间', () => {
const result = dataset4
.values()
.filter(item => item.active)
.map(item => ({ ...item, doubled: item.value * 2 }))
.filter(item => item.doubled > 500)
.map(item => ({ id: item.id, final: item.doubled + 100 }))
.take(15)
.toArray();
return result;
}, 10);
// Iterator Helpers - 内存
const iteratorHelpersMem4 = memoryBenchmark('Iterator Helpers (多次链式调用) - 内存', () => {
const result = dataset4
.values()
.filter(item => item.active)
.map(item => ({ ...item, doubled: item.value * 2 }))
.filter(item => item.doubled > 500)
.map(item => ({ id: item.id, final: item.doubled + 100 }))
.take(15)
.toArray();
return result;
});
const timeImprovement4 = ((arrayMethodTime4 - iteratorHelpersTime4) / arrayMethodTime4 * 100).toFixed(2);
const memImprovement4 = ((arrayMethodMem4 - iteratorHelpersMem4) / arrayMethodMem4 * 100).toFixed(2);
console.log(`\n性能提升: 时间 ${timeImprovement4}%, 内存 ${memImprovement4}%`);
// ============ 总结 ============
console.log('\n' + '='.repeat(60));
console.log('总结');
console.log('='.repeat(60));
console.log(`
场景 1 (过滤+转换+取前N项):
时间提升: ${timeImprovement1}%
内存提升: ${memImprovement1}%
场景 2 (嵌套数据扁平化):
时间提升: ${timeImprovement2}%
内存提升: ${memImprovement2}%
场景 3 (查找第一个匹配项):
时间提升: ${timeImprovement3}%
内存提升: ${memImprovement3}%
场景 4 (复杂链式调用):
时间提升: ${timeImprovement4}%
内存提升: ${memImprovement4}%
结论:
- Iterator Helpers 在需要"取前 N 项"的场景下优势明显
- 时间和空间开销都能显著降低
- 数据规模越大,提升越显著
- 惰性求值避免了不必要的中间数组创建
- 在查找场景下,Iterator Helpers 可以提前终止,避免遍历整个数组
`);
console.log('\n提示: 运行时加上 --expose-gc 参数可以获得更准确的内存测试结果');
console.log('命令: node --expose-gc iterator-helpers-benchmark.js');
实际运行输出
在我的环境(Node.js 22+)下,使用 node --expose-gc iterator-helpers-benchmark.js 运行上面的代码,得到以下结果:
============================================================
测试场景 1: 大数据集过滤 + 转换 + 取前 10 项
数据规模: 100,000 条
============================================================
传统数组方法 (filter + map + slice) - 时间:
平均: 1.545ms
最小: 0.920ms
最大: 2.993ms
内存增长: 3.38 MB
Iterator Helpers (filter + map + take) - 时间:
平均: 0.019ms
最小: 0.003ms
最大: 0.126ms
内存增长: 0.01 MB
性能提升: 时间 98.77%, 内存 99.75%
============================================================
测试场景 2: 嵌套数据扁平化 + 过滤 + 取前 20 项
数据规模: 10,000 个父项,每个包含 10 个子项
============================================================
传统数组方法 (flatMap + filter + slice) - 时间:
平均: 3.716ms
最小: 2.263ms
最大: 8.936ms
内存增长: 4.03 MB
Iterator Helpers (flatMap + filter + take) - 时间:
平均: 0.018ms
最小: 0.004ms
最大: 0.120ms
内存增长: 0.01 MB
性能提升: 时间 99.53%, 内存 99.73%
============================================================
测试场景 3: 查找第一个匹配项(匹配项在数据集后半部分)
数据规模: 1,000,000 条
============================================================
传统数组方法 (filter + [0]) - 时间:
平均: 6.587ms
最小: 5.605ms
最大: 11.103ms
内存增长: 0.01 MB
Iterator Helpers (find) - 时间:
平均: 8.713ms
最小: 7.893ms
最大: 9.545ms
内存增长: 14.80 MB
性能提升: 时间 -32.27%, 内存 -194800.20%
============================================================
测试场景 4: 复杂链式调用(filter + map + filter + map + take)
数据规模: 50,000 条
============================================================
传统数组方法 (多次链式调用) - 时间:
平均: 1.421ms
最小: 0.840ms
最大: 2.797ms
内存增长: 5.33 MB
Iterator Helpers (多次链式调用) - 时间:
平均: 0.028ms
最小: 0.005ms
最大: 0.220ms
内存增长: 0.01 MB
性能提升: 时间 98.02%, 内存 99.75%
============================================================
总结
============================================================
场景 1 (过滤+转换+取前N项):
时间提升: 98.77%
内存提升: 99.75%
场景 2 (嵌套数据扁平化):
时间提升: 99.53%
内存提升: 99.73%
场景 3 (查找第一个匹配项):
时间提升: -32.27%
内存提升: -194800.20%
场景 4 (复杂链式调用):
时间提升: 98.02%
内存提升: 99.75%
结论:
- Iterator Helpers 在需要"取前 N 项"的场景下优势明显
- 时间和空间开销都能显著降低
- 数据规模越大,提升越显著
- 惰性求值避免了不必要的中间数组创建
- 在查找场景下,Iterator Helpers 可以提前终止,避免遍历整个数组
提示: 运行时加上 --expose-gc 参数可以获得更准确的内存测试结果
命令: node --expose-gc iterator-helpers-benchmark.js
从输出可以看到:
场景 1-2、4("取前 N 项"类场景):
- 时间提升:98%+
- 内存提升:99%+
- Iterator Helpers 在时间和空间上都有压倒性优势
场景 3(查找匹配项):
- 时间下降:32%(Iterator Helpers 更慢)
- 内存异常:这个结果看起来有问题,可能是 GC 时机导致的测量误差
- 这个场景不适合用 Iterator Helpers
关键发现:
- 内存优势极其明显:在适合的场景下,Iterator Helpers 的内存使用只有传统方法的 0.3%
- 中间数组是大头:场景 4 创建了 4 个中间数组,占用 5.33 MB;Iterator Helpers 几乎为零
- 不是所有场景都适用:场景 3 证明了 Iterator Helpers 不是银弹
如果你觉得这篇文章有帮助,欢迎关注我的 GitHub,下面是我的一些开源项目:
Claude Code Skills(按需加载,意图自动识别,不浪费 token,介绍文章):
- code-review-skill - 代码审查技能,覆盖 React 19、Vue 3、TypeScript、Rust 等约 9000 行规则(详细介绍)
- 5-whys-skill - 5 Whys 根因分析,说"找根因"自动激活
- first-principles-skill - 第一性原理思考,适合架构设计和技术选型
qwen/gemini/claude - cli 原理学习网站:
- coding-cli-guide(学习网站)- 学习 qwen-cli 时整理的笔记,40+ 交互式动画演示 AI CLI 内部机制
全栈项目(适合学习现代技术栈):
- prompt-vault - Prompt 管理器,用的都是最新的技术栈,适合用来学习了解最新的前端全栈开发范式:Next.js 15 + React 19 + tRPC 11 + Supabase 全栈示例,clone 下来配个免费 Supabase 就能跑
- chat_edit - 双模式 AI 应用(聊天+富文本编辑),Vue 3.5 + TypeScript + Vite 5 + Quill 2.0 + IndexedDB
VS Code 插件:
- vscode-ai-commit - 一键生成 commit message,支持 Conventional Commits,兼容任何 OpenAI 格式接口