我正在使用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中设置一个变量时,它实际上是在创建自己的实例,这看起来像是在工作……但是也许我误解了。
在性能方面,它们应该非常相似。但是,这实际上取决于设置变量后会发生什么。您是否要调用一个每次都会大量工作的函数?然后,最好使用第二个。
您不应该为微优化而烦恼,延迟几毫秒不会真正影响您的应用程序。
[此外,如果您需要亲自查看,则可以运行一些基准代码(不过,它不太准确)。它显示了每个功能运行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;
};
}
}
};
如评论中所述,较简单的版本很可能会更快-并且更易于阅读且不易出错。
虽然有您,但我建议一种完全不同的方法:计算象限,而不是使用一堆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
功能生成的机器代码(仅显示代码的核心部分,而不是功能设置和拆卸)。
当我们输入此代码时,四个功能参数存储在这些寄存器中:
r8
是x
。r11
是y
。rdx
是width
。rdi
是height
。
这是编译后的代码:
; 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上,当您可以避免分支时,通常可以提高性能。
但是同样,这些方法中的任何一种都可能足够快!如果您感兴趣,只需发布此替代方法。