-108

条件运算符===和赋值运算符=之间的性能有什么区别吗?我正在猫鼬中编写一些预保存钩子中间件,我想知道以下之间是否存在很大的速度差异:

UserSchema.pre('save', function (next) {
    if (!this.isModified()) {
        return next();
    }
    this.crm.isUpToDate = false;
    next();
});

UserSchema.pre('save', function (next) {
    if (!this.isModified()) {
        return next();
    }
    if (this.crm.update === true) {
        this.crm.isUpToDate = false;
    }
    next();
});

编辑:

感谢您的建设性意见。

基本上,它看起来在性能上没有太大差异(如上所述可以忽略不计)。感谢测试速度的酷工具http://jsperf.com/,我以前从未听说过它。

对于那些对代码感到疑惑的人,首先我在原始帖子中犯了一个明显的错误,然后当每个人试图向我指出它时我哭了,这可能是每个人都反对的原因。

这是我正在做的事情:

我有一个 mongoose 预保存中间件挂钩(用于 mongo 数据库),每次保存文档时都会运行该挂钩。在保存时,我检查文档是否已更新。如果是我将其设置crmIsUpToDate为假。当crmIsUpToDatecron 作业获得时,将设置为 true。在 cron 作业到达文档之前,可以多次运行此挂钩。

我不认为这对于这个问题来说是必要的,因为问题是进行比较===和进行分配之间是否有区别=。我什至不应该把代码放上去,因为它确实偏离了主要问题。

4

2 回答 2

51

当您使用非引用计数语言(JavaScript 不是)并执行大对象的赋值('=',导致复制操作)时,它可能会“慢”。因此,检查该复制操作是否真的有必要可以为您节省大量时间。

但是 JavaScript 是一种原生引用计数语言:

object1 = {a: 1, b: 2};
object2 = object1;         // refcounting copy?
object1.a = 3;             // test by modifying the first object
console.log( object2.a );  // will return 3 => refcounting

=> 所以所有的赋值操作('=')都很便宜。

而且,更重要的是,您正在使用可能更快或至少与对象一样快的本机数据类型(bool,数字将相同)。
注意:字符串在 JavaScript 中不被引用,在这种情况下它们是一个例外。

所以,现在我们已经了解到这项任务很便宜。但是身份检查('===')呢?

在您的代码中,您必须通过对象this-> crm-> 逐渐减少update- 这需要一些额外的时间。然后必须检查类型(bool)的相同性,然后检查内容(false)是否相同。
所有这些都在程序流中添加了条件,在这些条件下,具有长管道的现代 CPU 可能会错误地猜测分支,从而导致停止并重新加载整个管道。这也浪费了相当多的 CPU 周期(尽管现代 CPU 现在在这方面做得很好)。

=> 这种比较('===')相当昂贵。

结论 #1:
您不应该通过可以轻松避免的昂贵测试来保护廉价代码。
当代码变得更昂贵时,测试将最终节省时间。这将导致:

结论 #2:
过早的优化是邪恶的!它可以使代码更难阅读,引入新的错误,使代码更大(也对缓存效率不利),...
=> 只优化那些你确定运行在性能问题中的代码部分 - 然后只基于分析信息。人类很不擅长猜测这里的影响......

于 2014-07-12T10:19:30.687 回答
8

当前的最佳答案在一个重要点上是不正确的:===与 类似=,因为它不会深入比较对象;它只是检查它们是否引用了内存中的相同对象。(if分支是这里唯一真正的罪魁祸首)

===条件运算符和赋值运算符之间的性能有什么区别=吗?

===不是条件运算符 -===是“严格相等比较”(或“身份”或“严格等于”)。(Javascript 的条件运算符的形式为condition ? expr1 : expr2

已经涵盖了分配varName = expression非常便宜:本质上,它获取expression内存中 where 的位置,并varName指向该位置。即使expression是一个巨大的对象,也不会发生深度复制。

但是对于严格平等比较来说,同样的事情在大多数情况下也是如此 -expr1 === expr2将评估为何true时:

  1. 两个表达式都是基元,并且都具有相同的类型和相同的值(除了NaN),或者

  2. 两个表达式都是对象,对象是内存中的同一个对象

检查两个对象表达式是否引用内存中的同一个对象非常便宜 - 它与获取对象的内存引用并具有指向该内存位置的变量(就像=那样)处于同一数量级。===不会深入比较每个嵌套的属性和值(除非您明确地使用JSON.stringifying 的两侧进行比较===,但在这种情况下,瓶颈是JSON.stringify,而不是===

带有if分支的代码:

if (this.crm.update === true) {
    this.crm.isUpToDate = false;
}

将比普通分配慢:

this.crm.isUpToDate = false;

因为逻辑分支很慢(相对);检查====分配非常快:

作为一般经验法则,分支比直线代码慢(在所有 CPU 和所有编程语言上)。- jmrk,V8 开发人员

这与著名问题背后的问题相同:为什么处理排序数组比处理未排序数组更快?

也就是说,虽然逻辑分支确实需要额外的资源,但在现代计算机上,效果很少显着 - 最好争取干净、可读的代码,并且只有在确定该部分导致性能后才考虑更改该部分瓶颈,否则您将使代码更难阅读,因为这通常是难以察觉的差异。

于 2019-04-03T01:40:54.620 回答