首页 > 解决方案 > 箭头函数和内存泄漏

问题描述

假设我为一个巨大数组的每个元素创建了一个箭头函数

someHugeArray.forEach(record => {
  const someValues = [...getAnotherHugeArray()]
  const sum = _.sumBy(someValues, 'total')

  record.getPrice = () => sum / record.quantity
})

这只是一个例子......所以在getPrice创建的环境中,我们有一个巨大的数组someValues,我们使用它,但实际上getPrice我们不再需要它,因为我们获得了所需的值并将其保存到sum.

用代码破坏它的价值有帮助吗

someValues = null

或者 javascript 引擎足够聪明,不会为函数的词法环境保留内存值,而函数的词法环境不被它使用?

标签: javascriptarrow-functions

解决方案


tl;博士

  • 根据 ECMAScript,绑定了完整的词法环境
  • 在实践中,如果可能,引擎会通过仅绑定使用的变量来优化这一点
  • 优化是不可能的,例如在eval()内部使用时

我发现了一个很棒的文章系列,其中对此进行了深入讨论:

这些文章很旧但仍然有效,您可以自己验证(见下文)。

对于您的示例:理论上someValues会被绑定(而不是垃圾收集),尽管它没有在record.getPrice闭包中使用。但实际上,只有您在那里使用的变量 ( sum) 是绑定的。绑定的事实对sum的绑定没有影响someValues,因为sum它是从 派生的someValues,但不需要进一步引用它(它被定义为不同的东西const sum = () => _.sumBy(someValues, 'total')

验证:在浏览器控制台中执行以下命令:

(() => {
    //eval(); // <- uncomment this line for second test
    const thisIsUsed = 1;
    const isThisBound = 2;
    return () => {
        debugger;
        return ('result: ' + thisIsUsed);
    }
})()();

当调试器启动时,查看“Scope”(Chrome)。您还可以将thisIsUsed和添加isThisBound到“观察”列表。

这是使用 Chrome(Canary,版本 85.0.4154.0)的屏幕截图:

Chrome 开发者工具调试器截图

使用当前的 Firefox(版本 76.0.1)可以观察到相同的行为。

根据 Dmitry Soshnikov 的文章,eval()可以打破优化。这很容易理解,因为引擎然后假设可以访问任何变量。也可以验证此行为,只需取消注释上面代码示例中的行。


推荐阅读