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

古利

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

假设我想将变量“ quadrant”设置为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中设置一个变量时,它实际上是在创建自己的实例,这看起来像是在工作……但是也许我误解了。

迈克尔·吉尔

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

当我得到您时,让我建议一种完全不同的方法:计算象限,而不使用一堆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转换为0true转换1

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

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

让我们看一下V8为该getQuadrant功能生成的机器代码(仅显示代码的核心部分,而不是功能设置和拆卸)。

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

r8x
r11y
rdxwidth
rdiheight

这是编译后的代码:

; 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上,当您可以避免分支时,通常可以提高性能。

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

如果您想知道如何获得该机器代码清单,可以创建一个名为JavaScript的独立文件quadrants.js,内容如下:

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

然后我使用以下命令运行它:

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

然后,我浏览了生成的code.txt文件以查找该getQuadrant功能的代码

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章