JS优化-在快速触发事件中不断设置变量

问题描述 投票:1回答:2

我正在使用Three.js编写脚本,其中很多变量取决于鼠标的位置。是否在每次移动事件触发时不断将变量设置为相同的值是否重要,还是仅在检测到更改时才设置变量?

假设我想将变量“象限”设置为1,2,3或4,具体取决于鼠标悬停在屏幕的哪一部分...我应该使用此:

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);

每次事件触发时,都会重置变量。还是仅当检测到更改时才设置变量,例如:

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);

将变量设置到内存的行为(即使它的值相同)是否比读取添加条件所需的额外代码行所花费的成本还要多?我本能地执行后者,因为它看起来比较整洁,并且在运行时需要较少的工作,但是我真的不知道这实际上如何转换为性能。我似乎记得读过,每次在js中设置一个变量时,它实际上是在创建自己的实例,这看起来像是在工作……但是也许我误解了。

javascript performance variables optimization memory
2个回答
0
投票

在性能方面,它们应该非常相似。但是,这实际上取决于设置变量后会发生什么。您是否要调用一个每次都会大量工作的函数?然后,最好使用第二个。

您不应该为微优化而烦恼,延迟几毫秒不会真正影响您的应用程序。

[此外,如果您需要亲自查看,则可以运行一些基准代码(不过,它不太准确)。它显示了每个功能运行1k次的平均时间(以秒为单位)

let sum1 = 0, sum2 = 0, quadrant;
for(i = 0; i < 1000; i++){

    let obj = calculate(1000);
    sum1 += obj.t1;
    sum2 += obj.t2;

}
console.log("avg for first: ", sum1 / 1000);
console.log("avg for second: ", sum2 / 1000);

function calculate(numIterations){
    
    //first function
    let start = Date.now();
    for(let i = 0; i < numIterations; i++){
        mouseMove(generateEventObject());
    }
    let t1 = (Date.now() - start) / 1000; 
    //second function
    start = Date.now();
    for(let i = 0; i < numIterations; i++){
        mouseMove2(generateEventObject());
    }
    let t2 = (Date.now() - start) / 1000; 
    return {t1, t2}
}

function generateRandom(max) {
    return Math.random() * max;
}

function generateEventObject() {
    return {
        clientX: generateRandom(window.innerWidth),
        clientY: generateRandom(window.innerHeight)
    }
}

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;
           }
    }
};

function mouseMove2(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;
               };
           }
    }
};

0
投票

如评论中所述,较简单的版本很可能会更快-并且更易于阅读且不易出错。

虽然有您,但我建议一种完全不同的方法:计算象限,而不是使用一堆if语句。

// 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

此代码之所以有效,是因为当您对布尔值使用算术运算符时,它会将false值转换为0,并将true值转换为1

我不知道这会更快还是会慢(您必须对其进行基准测试才能发现),但是由于您正在寻找解决问题的不同方法,所以我认为您可能会发现它很有趣。

[您可能想知道“这些乘除除不是很慢吗?”但是,现代JavaScript引擎(如大多数优化的编译器一样)可以将乘以2的乘方或除法转换为非常快速的移位操作。

[这是V8为getQuadrant功能生成的机器代码(仅显示代码的核心部分,而不是功能设置和拆卸)。

当我们输入此代码时,四个功能参数存储在这些寄存器中:

r8xr11yrdxwidthrdiheight

这是编译后的代码:

; 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]

一个可能的性能优势是该代码避免了if语句使用的分支。在现代CPU上,当您可以避免分支时,通常可以提高性能。

但是同样,这些方法中的任何一种都可能足够快!如果您感兴趣,只需发布​​此替代方法。

© www.soinside.com 2019 - 2024. All rights reserved.