我阅读了有关JavaScript优化的文章后,我意识到需要删除代码中的封闭以优化内存使用。
我的一种代码模式是尽可能多地使用Array.forEach()
,即使在这种情况下也是如此:
-
使用数组中的项目修改外部对象
function updateSomething(array, toChange) { array.forEach(item => { toChange[item] = ''; // do something to change the object }); }
-
创建嵌套
Array.forEach()
array1.forEach(item1 => { array2.forEach(item2 => { doSomething(item1, item2); }); });
显然,Array.forEach()
中使用的回调函数会创建关闭。那么,在这些情况下,我是否滥用Array.forEach()
?我应该回到对性能敏感项目中的for
循环吗?
跟进
我在for
循环和Array.forEach()
功能上进行了一些实验,并使用节点v7.6.0进行了一些实验。我没有关于绩效测试的事先经验。所以让我知道我是否做错了。
-
Array.forEach()
访问外部变量// get the baseline of memory usage gc(); let baseline = process.memoryUsage(); console.log(`Baseline memory usage: ${baseline.heapUsed / 1024 } KB`); let data = { test: 0 }; function test(data) { let array1 = new Array(1000000).fill(1); array1.forEach((item) => { data.test = data.test + item; }); } test(data); let final = process.memoryUsage(); console.log(`Final memory usage: ${final.heapUsed / 1024} KB`); console.log(`Memory used: ${(final.heapUsed - baseline.heapUsed) / 1024} KB`);
结果
Baseline memory usage: 2747.671875 KB Final memory usage: 11027.34375 KB Memory used: 8279.671875 KB
-
for
循环// get the baseline of memory usage gc(); let baseline = process.memoryUsage(); console.log(`Baseline memory usage: ${baseline.heapUsed / 1024 } KB`); let data = { test: 0 }; function test(data) { let array1 = new Array(1000000).fill(1); for(let i = 0; i < 1000000; i++) { data.test = data.test + array1[i]; } } test(data); let final = process.memoryUsage(); console.log(`Final memory usage: ${final.heapUsed / 1024} KB`); console.log(`Memory used: ${(final.heapUsed - baseline.heapUsed) / 1024} KB`);
结果
Baseline memory usage: 2747.453125 KB Final memory usage: 11031.546875 KB Memory used: 8284.09375 KB
-
嵌套
Array.forEach()
// get the baseline of memory usage gc(); let baseline = process.memoryUsage(); console.log(`Baseline memory usage: ${baseline.heapUsed / 1024 } KB`); let array1 = new Array(1000).fill(1); let array2 = new Array(1000).fill(2); array1.forEach((item, index) => { array2.forEach(item2 => { array1[index] = array1[index] = item2; }) }); let final = process.memoryUsage(); console.log(`Final memory usage: ${final.heapUsed / 1024} KB`); console.log(`Memory used: ${(final.heapUsed - baseline.heapUsed) / 1024} KB`);
结果
Baseline memory usage: 2748.109375 KB Final memory usage: 3368.5859375 KB Memory used: 620.4765625 KB
-
嵌套
for
循环// get the baseline of memory usage gc(); let baseline = process.memoryUsage(); console.log(`Baseline memory usage: ${baseline.heapUsed / 1024 } KB`); let array1 = new Array(1000).fill(1); let array2 = new Array(1000).fill(2); for (let i = 0; i < 1000; i++) { for (let j = 0; j < 1000; j++) { array1[i] = array1[i] + array2[j]; } } let final = process.memoryUsage(); console.log(`Final memory usage: ${final.heapUsed / 1024} KB`); console.log(`Memory used: ${(final.heapUsed - baseline.heapUsed) / 1024} KB`);
结果
Baseline memory usage: 2745.59375 KB Final memory usage: 3234.2890625 KB Memory used: 488.6953125 KB
结论
测试#1和#2的存储器使用率增加的差异小于0.1%。因此,这表明Array.forEach()
确实具有与传统for
环路相同的内存效率,即使它正在访问外部变量,并且似乎会创建封闭。魔术是在内部完成的。
注意到,在测试#3中,array2.forEach()
的回调功能初始化了1000次。这可以解释为什么测试#3比测试#4使用更多的内存。
我意识到需要删除代码中的封闭以优化内存使用。
用于内存使用,只有您 store 的关闭。当您遇到内存问题时,您应该检查是否有很多实例的类,每个实例都有自己的封闭实例。这并不意味着您通常应该避免关闭。
我的一个代码模式是尽可能多地使用
Array.forEach()
不要。鉴于您正在使用ES6,因此您应该尽可能多地使用for … of
(对于命令循环)。
显然
Array.forEach()
中使用的回调函数创建关闭
是的,但是在示例中,您表明它们无法避免(无法将其移至静态功能)。鉴于它们只能持续到forEach
呼叫,并且将立即被垃圾收集,也没有内存应变。
但是,正如您链接的文章所解释的那样,封闭仍然是昂贵的(与完全不创建它们相比)。
我应该回到绩效敏感项目中的
for
循环吗?
是的,肯定(至少在中 对性能敏感的位置 - 不会全部项目)。但是,原因不是关闭成本,通常是函数的呼叫开销,forEach
无法完全优化。