-111

Is there any difference in performance between the conditional operator === and the assignment operator =? I am writing some pre-save hook middleware in mongoose and I am wondering if there is much of a speed difference between:

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

and

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

EDIT:

Thanks for the constructive comments.

Basically, it doesn't look like there is much of a difference in the performance (as stated above it's negligible). Thanks for the cool tool for testing speed http://jsperf.com/, I had never heard of it before.

For those of you who are wondering about the code, first off I made a blatant error in my original post, then when everyone tried to point it out to me I cried, that's probably the reason why everyone downvoted.

Here is what I am doing:

I have a mongoose pre-save middleware hook (for a mongo database) where the hook gets run every time a document is saved. At the point of save I check if the document was updated. If it was I set the crmIsUpToDate to false. The crmIsUpToDate will get set to true when a cron job gets. This hook can be run many times before the cron job gets to the document.

I didn't think this was all that necessary for the question because the question was if there is a difference between doing a comparison === and doing an assignment =. I shouldn't have even put the code up because it really detracted from the main question.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
ChewOnThis_Trident
  • 2,105
  • 2
  • 18
  • 22
  • 14
    1) any performance gain is going to be negligible; 2) http://jsperf.com – John Dvorak Jul 16 '13 at 20:53
  • 22
    Those two examples don't do the same thing you know ? – adeneo Jul 16 '13 at 20:54
  • 1
    I would be amazed if there were any appreciable difference between these two, but the only way to be sure is to benchmark it at the sort of loads you're expecting. – Jon Kiparsky Jul 16 '13 at 21:04
  • 5
    It's not about asking the questions; what you're talking about is the very definition of micro-optimization. Check this [jsperf](http://jsperf.com/assicomp) test, play with it (moving the 'invalid' block from the beginning to the end, detaching it completely) - and you will see that the difference, if any, won't be worth your attention completely. – raina77ow Jul 16 '13 at 21:37
  • 31
    You are running this code once before saving an user in the table. This is like wondering if dropping a bucket of water into the Atlantic Ocean will make ships go faster or something. – Esailija Jul 16 '13 at 21:39
  • 4
    @ChewOnThis_Trident: If you know they don't do the same thing, then I would think you also know that it's not a reasonable comparison. Either you need the `this.crm.isUpToDate === false`, or you don't. If you need it, then the performance difference isn't relevant... because you need it. If you don't need it, then why is it there? –  Jul 16 '13 at 21:40
  • The question does not make sense. How can we compare the performance of conditional statements and assignment operators when **they do not address the same task**? You might as well ask, which is faster: driving in order to get to work, or using a hairdryer to dry your hair? – Karl Knechtel Jan 04 '23 at 06:32
  • Running this code once before saving a user in the table is akin to questioning whether dropping a bucket of water into the vast Atlantic Ocean will have any impact on speeding up ships or similar matters. – Dmitrii Malygin May 17 '23 at 12:03

2 Answers2

54

When you have a non-refcounting language (which JavaScript isn't) and doing an assignment ('=', resulting in a copy operation) of a big object it can be "slow". So a check if that copy operation is really necessary can save you a significant amount of time.

But JavaScript is a native refcounting language:

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

=> so all assignment operations ('=') are quite cheap.

And, even more, you are working with a native data type (bool, numbers would be the same) that might be even faster or at least as quick as objects.
NOTE: strings are not refcounted in JavaScript, they are an exception in this case.

So, right now we have learned that the assignment is cheap. But what about the identity check (the '===')?

In your code you must wind your way down through the object this -> crm -> update - this takes some additional time. And then the identicality of the type (bool) must be checked and then if the content (false) is the same.
All of this are adding conditions in the program flow where modern CPUs with their long pipelines might guess the branch wrongly creating a stall and a reload of the full pipeline. This also wastes quite a lot of CPU cycles (although the modern CPUs are quite good at this now).

=> This comparison ('===') is quite expensive.

Conclusion #1:
You shouldn't protect a cheap code by an expensive test that can be easily avoided.
When the code gets more expensive a point will come where the test will save time at the end. This leads to:

Conclusion #2:
Premature optimisation is evil! It can make code harder to read, introduce new bugs, makes code bigger (also bad for cache efficiency), ...
=> Only optimize those parts of the code where you are sure you are running in a performance problem - and then only based on profiling informations. Humans are quite bad at guessing the effects here...

Chris
  • 3,265
  • 5
  • 37
  • 50
9

The current top answer is incorrect on an important point: === is similarly inexpensive to =, because it does not deeply compare objects; it simply checks whether they reference the same object in memory. (The if branch is the only real culprit here)

Is there any difference in performance between the conditional operator === and the assignment operator =?

=== is not the conditional operator - === is "Strict Equality Comparison" (or "identity", or "strict equals"). (Javascript's conditional operator is of the form condition ? expr1 : expr2)

It's already been covered that assignment with varName = expression is very cheap: essentially, it takes the location of where expression is in memory, and makes varName point to that location as well. No deep copying occurs, even when expression is a huge object.

But the same sort of thing is true for Strict Equality Comparison, for the most part - expr1 === expr2 will evaluate to true when either:

  1. Both expressions are primitives, and both are of the same type and same value (with the exception of NaN), or

  2. Both expressions are objects, and the objects are the same object in memory.

Checking whether two object expressions refer to the same object in memory is extremely cheap - it's on the same order of magnitude as taking the memory reference of an object and having a variable point to that memory location (as = does). === does not deeply compare every nested property and value (unless you explicitly do so with something like JSON.stringifying both sides of the ===, but in that case, the bottleneck is the JSON.stringify, not the ===)

The code with the if branch:

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

will be slower than the plain assignment:

this.crm.isUpToDate = false;

because logical branches are slow (relatively); the === check and = assignment are quite fast:

As a general rule of thumb, branches are slower than straight-line code (on all CPUs, and with all programming languages). -jmrk, V8 developer

This is the same issue behind the famous question: Why is it faster to process a sorted array than an unsorted array?

That said, while logical branches do require extra resources, on modern computers, the effect is rarely significant - it's better to strive for clean, readable code, and only consider changing such a section after you're sure that that section is causing a performance bottleneck, otherwise you'll make the code harder to read for what's often an imperceptible difference.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320