JS Optimization – constantly setting variables on fast fire events Code Answer

I am working on a script using Three.js where a lot a variables depend on mouse position. Does it matter if I am constantly setting variables to their same value each time the move event fires, or should I only set a variable when a change is detected?

Let’s say I want to set a variable “quadrant” to 1,2,3 or 4 depending upon which part of the screen the mouse is over… should I use this :

var quadrant;
function mouseMove(e){
    var mouse;
    mouse.x = e.clientX;
    mouse.y = e.clientY;
    if(mouse.x < window.innerWidth / 2){
          if(mouse.y < window.innerHeight / 2){
              quadrant = 1;
           } else {
              quadrant = 3;
           }
     } else {
          if(mouse.y < window.innerHeight / 2){
              quadrant = 2;
           } else {
              quadrant = 4;
           }
    }
};

window.addEventListener('mousemove', mouseMove);

Which will reset the variable every time the event fires. Or should I only be setting variables when a change is detected, like this :

var quadrant;
function mouseMove(e){
    var mouse;
    mouse.x = e.clientX;
    mouse.y = e.clientY;
    if(mouse.x < window.innerWidth / 2){
          if(mouse.y < window.innerHeight / 2){
               if(quadrant != 1){
                     quadrant = 1;
               }
           } else {
               if(quadrant != 3){
                     quadrant = 3;
               };
           }
     } else {
          if(mouse.y < window.innerHeight / 2){
               if(quadrant != 2){
                     quadrant = 2;
               };
           } else {
               if(quadrant != 4){
                     quadrant = 4;
               };
           }
    }
};

window.addEventListener('mousemove', mouseMove);

Does the act of setting a variable to the memory (even if it’s to the same value) cost more than it takes to read the extra lines of code necessary to add the conditions? I instinctively do the latter as it seems tidier and like less work at runtime, but I really have no idea how this actually translates to performance. I seem to remember reading that each time a variable is set in js that it’s actually creating an instance of itself, which seems like work… but maybe I misunderstood.

Answer

As noted in the comments, the simpler version is very likely to be faster – and it’s easier to read and less error-prone too.

While I’ve got you, let me suggest a completely different approach: calculate the quadrant instead of using a bunch of if statements.

// Calculate the quadrant for a given x and y and width and height.
// The quadrants are defined like this:
//
// +---+---+
// | 1 | 2 |
// +---+---+
// | 3 | 4 |
// +---+---+

function getQuadrant( x, y, width, height ) {
    return 1 +
        ( x >= width / 2 ) +
        ( y >= height / 2 ) * 2;
}

console.log( getQuadrant( 25, 25, 100, 100 ) );  // 1
console.log( getQuadrant( 75, 25, 100, 100 ) );  // 2
console.log( getQuadrant( 25, 75, 100, 100 ) );  // 3
console.log( getQuadrant( 75, 75, 100, 100 ) );  // 4

This code works because when you use an arithmetic operator on a boolean value, it converts a false value to 0 and a true value to 1.

I don’t know if this will be faster or slower (you would have to benchmark it to find out) but since you are looking at different approaches to solving the problem, I thought you might find it interesting.

You may wonder “aren’t those multiplies and divides slow?” But modern JavaScript engines, like most optimizing compilers, can convert multiplies or divides by a power of 2 into a very fast bit-shifting operation.

Let’s take a look at the machine code that V8 generates for the getQuadrant function (just showing the core part of the code, not the function setup and teardown).

When we enter this code, the four function parameters are stored in these registers:

r8 is x.
r11 is y.
rdx is width.
rdi is height.

And here’s the compiled code:

; Divide height and width by 2 for the comparisons below
sarl rdi, 1
sarl rdx, 1

; Compare y with half the height and set rcx to 0 or 1
cmpl rdi,r11
setlel cl
movzxbl rcx,rcx

; Compare x with half the width and set rdx to 0 or 1
cmpl rdx,r8
setlel dl
movzxbl rdx,rdx

; Set rdx to the final result, calculated in a single instruction
leal rdx,[rdx+rcx*2+0x1]

One likely performance advantage is that this code avoids the branches used by the if statements. On modern CPUs, when you can avoid branches, it is often a performance win.

But again, any of these approaches will likely be more than fast enough! Just posting this alternative method in case it is of interest to you.

If you’re curious how I got that machine code listing, I created a standalone JavaScript file called quadrants.js with this content:

function getQuadrant( x, y, width, height ) {
    return 1 +
        ( x >= width / 2 ) +
        ( y >= height / 2 ) * 2;
}

// We need to actually do something with the result returned by getQuadrant,
// otherwise the JavaScript engine may notice that the result is unused and
// it may skip compiling the function body entirely.

quadrants = [];

for( let i = 0;  i < 1000000;  ++i ) {
    quadrants.push( getQuadrant( 25, 25, 100, 100 ) );
    quadrants.push( getQuadrant( 75, 25, 100, 100 ) );
    quadrants.push( getQuadrant( 25, 75, 100, 100 ) );
    quadrants.push( getQuadrant( 75, 75, 100, 100 ) );
}

// Log the first few results as a sanity check

console.log( quadrants.length );
for( let i = 0;  i < 16;  ++i ) {
    console.log( quadrants[i] );
}

Then I ran it with this command:

node --print-opt-code --code-comments quadrants.js >code.txt

And then I looked through the generated code.txt file to find the code for the getQuadrant function.

Related Posts

© No Copyrights, All Questions are retrived from public domain.
Tutorial Guruji