JavaScript: `delete` 关键字的性能限制

标签 javascript v8

我正在尝试更好地了解 JS 在幕后的工作方式,我过去听说 delete 关键字(特别是 node.js 或使用 V8 的浏览器)会导致性能不佳,所以我想看看我是否能弄清楚使用该关键字的好处/坏处。

我认为不使用 delete 的原因是删除属性会导致重建隐藏类转换,从而重新编译内联缓存。但是,我相信对象原型(prototype)将不再枚举该属性也是事实,因此如果对象被大量使用,前期成本最终可能会得到返回。

所以:

  1. 我关于权衡的假设是否正确?
  2. 如果它们是正确的,一个因素是否比另一个因素更重要(例如,重建 IC 是否比许多原型(prototype)枚举昂贵得多)?

最佳答案

这里是 V8 开发人员。简短回答:“视情况而定”。

拥有未使用的属性(property)并没有什么坏处;除非您实际执行显式枚举,否则没有一般的“枚举成本”。换句话说,只有当你发现自己在做这样的事情时,“枚举成本”才会存在:

for (var p in object) {
  if (p === old_property_that_I_could_have_deleted) continue;
  /* process other properties... */
}

很难给出具体答案(或提供一个效果可测量的典型示例)的关键原因是效果是非本地的:它们都取决于您对对象的确切操作有问题,以及您的应用程序的其余部分在做什么。从一个对象中删除一个属性可能会导致对其他对象的操作变慢。或者更快。这取决于。

退后一步,看看高级情况:JavaScript 作为一种语言,假定对象表示为字典。删除字典中的条目应该完全没问题,这就是 delete 运算符存在的原因。在实践中,如果引擎将对象存储为字典,而是更像是某种东西,那么引擎可以为读取密集型应用实现巨大的性能改进,这是迄今为止最常见的情况类似于 C/C++ 结构。然而,这样的对象表示(1)当属性被删除时通常很难/效率低下,并且(2)即使是第一次删除属性,引擎也可能会很好地解释为程序员希望这个特定对象表现得像字典,所以它可能会切换内部表示。如果快速修改字典是您想要的,那很好(它甚至会提供好处);但是,如果您希望对象保持修改速度慢/读取速度快的模式,您会认为转换到修改速度快/读取速度慢的字典模式是一个性能问题。

值得庆幸的是,现在有一个很好的解决方案:当您需要字典时,使用 MapSet。引擎可以(并且通常会)假设您想要从这些条目中删除条目,因此优化了实现以使其成为可能而没有负面影响;特别是不涉及隐藏类。

关于您的假设的几点评论:删除属性会使对象(大部分)离开隐藏类转换系统,不会重建任何转换。没有单一的全局“内联缓存”,有许多内联缓存散布在您的函数中。它们不会被重建,它们只是过渡到越来越慢的模式,因为它们必须处理更多不同的情况。 (这通常是缓存的工作原理:缓存单个案例可以提供巨大的加速;另一方面,如果您有与执行一样多的不同案例,那么缓存只会浪费时间和内存,而不会提供任何好处。)字典模式对象取决于整体情况:处理(大部分)字典模式对象的内联缓存通常表现出介于(1)只需要处理共享单个相同隐藏类的对象的内联缓存和( 2) 必须处理成百上千个不同隐藏类的内联缓存。

关于JavaScript: `delete` 关键字的性能限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59431589/

相关文章:

c++ - 在 V8 中,为什么 Isolate::GetCurrent() 返回 NULL?

javascript - 递归 - Node 内存不足

javascript - 我应该担心清理 Node.js 中的大对象还是留给垃圾收集器?

javascript - 在 Chrome V8 中实例化从 Object 扩展的类时,super() 不传递参数

javascript - 在 HTML5 Canvas 中填充后抗锯齿边缘?

javascript - 之前的web form录入数据后,如何让web form出现?

javascript - 页面刷新后保留下拉列表的选定值

javascript - 是什么使得预解析函数比完整解析更快?

php - 禁用输入字段中的 html 标签、php、脚本

javascript - 删除 HTML 中的部分标记