Javascript性能,条件语句与赋值运算符

时间:2013-07-16 20:51:45

标签: javascript performance operators

条件运算符===与赋值运算符= 之间的性能是否存在差异?我正在用猫鼬写一些预先保存的钩子中间件,我想知道它们之间是否存在很大的速度差异:

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设置为false。当cron作业到达时,crmIsUpToDate将设置为true。在cron作业到达文档之前,可以多次运行此挂钩。

我认为这不是问题所必需的,因为问题在于进行比较===和做作业=之间是否存在差异。我甚至不应该把代码放上去,因为它确实减少了主要问题。

2 个答案:

答案 0 :(得分:45)

如果您使用非引用语言(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:
过早优化是邪恶的!它可以使代码更难阅读,引入新的错误,使代码更大(也有利于缓存效率),...
=>只优化您确定在性能问题中运行的代码部分 - 然后仅基于分析信息。人类在这里猜测效果是非常糟糕的......

答案 1 :(得分:1)

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

  

条件运算符===和赋值运算符=之间的性能是否有区别?

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

已经知道使用varName = expression进行分配非常便宜:本质上,它获取expression在内存中的位置,并使varName也指向该位置。即使expression是一个巨大的对象,也不会发生深层复制。

但是对于严格平等比较而言,同样的情况也是如此,在大多数情况下-expr1 === expr2在以下任一情况下均将得出true

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

  2. 两个表达式都是对象,并且这些对象是内存中的相同对象

检查两个对象表达式是否引用内存中的同一对象非常便宜-与获取对象的内存引用并具有指向该内存位置的可变点(如=的数量级相同确实)。 ===不会深入比较每个嵌套的属性和值(除非您通过JSON.stringify两侧的===进行显式比较,但在这种情况下,瓶颈是{{ 1}},而不是JSON.stringify

带有===分支的代码:

if

会比普通作业慢:

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

因为逻辑分支较慢(相对); this.crm.isUpToDate = false; 检查和===分配非常快:

  

一般而言,分支比直线代码(在所有CPU上以及所有编程语言中)慢。 -jmrk, V8 developer

这是著名问题:Why is it faster to process a sorted array than an unsorted array?

背后的相同问题

也就是说,尽管逻辑分支确实需要额外的资源,但是在现代计算机上,效果很少显着-争取使用干净,可读的代码更好,并且只考虑更改 >在确定该段会导致性能瓶颈之后,否则,由于通常难以察觉的差异,您将使代码难以阅读。