【问题标题】:Considering code for unknown Javascript engine, what considerations make some of the most impact on execution speed and memory conservation?考虑未知 Javascript 引擎的代码,哪些因素对执行速度和内存节省影响最大?
【发布时间】:2017-02-08 03:44:56
【问题描述】:

然后,我想,更完整的问题是,“当 Javascript 引擎已知时(基于每个流行的引擎),这些考虑因素如何受到影响。”

我觉得我需要询问“社区”的原因是,像 Strongloop 这样创建 Node.js 之类的东西的人,也编写了 util.inherits 之类的代码,一个函数在其中,而不是:TheConstructorFunction.prototype.constructor = TheConstructorFunction 他们创建了一个属性定义本身有 4 个属性被设置:

ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
        value: ctor,
        enumerable: false,
        writable: true,
        configurable: true
    }
});

这对我来说似乎效率低下,但是,与编写此类代码的作者相比,我在 3 年内一直在努力编写更好的 Javascript。有没有解释为什么这有效或无效?

一个答案说 util.inherits 并不是低效的,因为子类操作很少见。但是考虑到一些库处理在构建到测试结果观察之间发生的成百上千的子类操作,如果 Node.js 内部使用 util.inherits 那么这会影响其使用者的开发时间。我认为,在这个级别上,效率确实很重要,我希望 util.inherits 不会在内部使用。我什至不明白 util.inherits 的目的。为什么要拥有它?我认为它促进了复合效率低下。 require('util').inherits(C1,C2); 几乎是同义词,并且可能比 C1.prototype=Object.create(C2.prototype); C1.prototype.constructor=C1; 慢如果它只是为了吸引消费者,我对此很冷静。我担心这些专业人士是否在内部使用该功能,因为更大的库将取决于 Node.js 的效率。至于使.constructor 不可枚举......我认为它的“可枚举性”很重要的情况很少见,应该留给消费者,但如果内部操作取决于 util.inherits,这不是真的留给消费者。

【问题讨论】:

  • 您给出的ctor.prototype 的示例与您与之比较的prototype.constructor 不同。那是苹果对橘子。
  • "一些库处理在构建到测试结果观察之间发生的成百上千的子类操作" - 真的吗?什么让你有那个想法?不,即使这个规模也无关紧要,例如比较从磁盘读取源文件。 “几乎是同义词,可能更慢” - 实际上两者都不是。如果您对此感到好奇,请自己对它们进行基准测试。不,标准库函数不会导致效率低下,它们会促进简单,这比微优化可以为开发人员节省更多的时间。
  • @Bergi,你可能是对的,我接受你的挑战。我将在不久的将来的某个时候对它们进行基准测试。因为,如果你是对的,那么我只是在浪费更多的时间去思考这些。但如果你错了,那么你和一大群博主/教育者/专业人士正在传播一个相当令人震惊的概念。我编写了一个 PHP 风电场管理 SaaS,它根据请求的类型使用了近 20-50 个不同的类,我正在考虑在 Node.js 中实现该系统,但我计划使用一个类似于 Wordpress 的底层系统作为其引擎。 ..所以有一个例子。

标签: javascript performance memory execution javascript-engine


【解决方案1】:

JavaScript 引擎的作者最好回答这个问题。

这是一个称为性能调整的过程。

Here's Google's guideHere's Mozilla's guide.

让 Node.js 快速运行 javascript 是 Strongloop 业务的核心。他们采取了javascript优化seriously

有一些陷阱,例如this

不过,大多数情况下,不要阻塞事件循环 - 使用 Promise、异步操作、回调等。

用合理的实际测试用例对您的代码进行基准测试。确保检查覆盖范围。

一旦找到了寻找性能调优的主要原因,就必须开始深入挖掘。你必须分析你的代码。

Thorsten Lorenz 有一个老化但仍然主要相关的GitHub repository,其中包含许多有用的内部 V8 信息。

有很多开发者发帖blog articleslike this guy。你必须确保他们知道他们在说什么。他会的。

Bluebird 是一个众所周知的 Promises 实现,是正确优化的巅峰之作。他们有 an articlea guide 在他们注意到的事情上,这些事情只是扼杀优化的常见事情。

更新

您给出的 util.s 实现继承链的示例可能应该是一个单独的问题。我不确定他们是否在那里修补猴子,我必须查看其余的类和原型。

请参阅this MDN article,了解实现继承的已知方法的优缺点和变体,特别是Object.create 的使用,以及其他方法。

扩展内置原型(又名“猴子补丁”) 的唯一充分理由是向后移植较新的 JavaScript 引擎的功能;例如 Array.forEach 等。

Here's 关于为什么会发生这种事情的一些推理。我answered a question 不久前关于将一个类注入到继承链的顶部,以便为所有子级添加扩展方法。这不是一个好主意。

原来,util.jsinherits 实现中的 Object.create 最初可能是一种优化尝试。根据early revisions,它使原型隐式不可变,理论上提高了方法解析性能。学究式地说,它从来都不是正确的,而且本质上一直是围绕 JavaScript 的原型继承功能进行的破解。新修订版将其替换为 Object.setPrototypeOf

编辑:如果您对此投了反对票,我将不胜感激。

【讨论】:

  • 如果我发现任何更重要的一般细节,我会在此基础上进行构建。性能调优可以非常深入。 Check out this question.
  • 我编辑了我的问题并将prototype.constructor 限定为TheConstructorFunction.prototype.constructor... 这与他们的ctor.prototype 构造函数属性定义相同。我知道他们这样做是为了使其不可枚举,但我不明白为什么。如果,我正在创建一个 Collection 类型类,好吧......也许我会继续让某些属性不可枚举。但是对于任何其他类型的类,我不确定是否值得“隐藏”构造函数属性的额外麻烦。我只是到处都看到这种臃肿,这让我怀疑即使是专业人士也知道他们在做什么。
  • 您是否有一个特定的文件可供您参考?啊对,是util.inherits in util.js...
  • this revision (gg. Michaël Zasso) 摆脱了Object.create 会让你更快乐吗? :)
  • 哈哈哈,我也不知道……现在得去研究一下V8对E6的Object::setPrototypeOf函数的实现。我的全部观点是:严重 util.inherits - 只是,为什么?就好像他们只是想避免做重要的工作。让我们看看我们可以生成和需要多少个模块,因为它非常方便。我想,把效率抛到窗外是相当方便的。我只是不明白,Javascript 继承需要两行代码。为什么需要一个全新的模块并调用一个成员函数(也是两行代码)来做同样的事情?真的方便吗?
【解决方案2】:

这对我来说似乎效率低下

没有。效率在这里并不重要。子类化是一种罕见的操作,即使代码比简单赋值慢(很可能没有太大区别),这也不会影响性能。

重要的是正确性,尤其是像utils.inherit 这样无处不在的库函数。那么他们为什么要使用属性属性呢?使 .constructor 不可枚举,就像它是标准的 .prototype 对象,这些对象是本机创建的,因此通常是预期的。

鉴于此处不需要考虑速度和内存,因此您似乎期望的优化不会在此处进行。

【讨论】:

  • 我更新了我的答案,因为这里没有足够的空间来解决您的结论。但是想想你在说什么......我读的是:“对于像 utils.inherits 这样无处不在的库函数,无论是速度还是内存都不需要考虑” 最重要的是“正确性”。我认为正确性很重要,当然。好吧,最好是这样,因为如果不是,那么它就坏了。但这是我的问题;我看到了很多(太多)允许次优代码的理由。
  • @flcoder 正确的代码是最佳代码 :-) 我的论点是专门针对 util.inherits,其他实际上对性能至关重要的函数(例如 Node 的 Stream 实现) 优化到最后的细节,但即使在那时也不会牺牲正确性。
  • 我明白你在说什么......因为我到处都听到了......我猜这就是教授所教的;当您感觉某段代码不需要关注优化时,膨胀是可以的。首先,我认为 util.inherits 完全没用,其次,我同意,用你的话来说,它“无处不在”,这让我感到不安。这就是“专业人士”的滚动方式......:P 这就是为什么我向整个社区提出我的问题。我想看看其他人认为可靠的 Javascript 优化建议的来源。
  • 我在实现中看不到任何膨胀......在保持正确性的同时不能缩短很多。 “我认为 util.inherits 完全没用” - 它可能适用于 ES6 类,但它之前确实有帮助。就像所有 util 库函数一样,它提供了一种简单可靠的方式来完成一项琐碎的任务。你不认为它经常被使用是有原因的吗?关于“可靠的 Javascript 优化建议”,您会总是将“避免premature optimisation”作为第一条规则。 util.inherits 就是一个很好的例子。
  • @Bergi 为了正确起见而悬而未决和过早优化之间是有区别的。围绕继承的行为会对编译器性能产生不利影响。与 bluebird 合作后,您必须阅读 this。仅仅使用__proto__ 会禁用优化。具体来说,优化的目标是正确性,因此您不必优化,只要正确即可。
猜你喜欢
  • 1970-01-01
  • 2011-01-04
  • 2013-08-04
  • 1970-01-01
  • 2021-04-21
  • 2011-09-29
  • 1970-01-01
  • 2017-10-09
  • 2012-12-31
相关资源
最近更新 更多