如果将JS循环体中用到的变量都在循环体外部进行声明,并对自定义类型进行了初始化,这样做是否性能更好,针对此疑问在Chrome浏览器中进行测试。
测试
测试环境为chrome,测试情况分为三种,如下:
- 变量声明位于循环体内部
- 变量声明位于循环体外部,但未初始化
- 变量声明位于循环体外部,并初始化
对不同数据类型进行测试,包括:
- 数字
- 布尔型
- 字符串
- THREE.Vector3
- THREE.Spherical
累计测试100次,统计总耗时(单位:ms),测试结果如下表:
数据类型 | 情况1 | 情况2 | 情况3 | 备注 |
---|---|---|---|---|
数字 | 19732 | 19153 | 19273 | 每次循环10000000次 |
布尔型 | 32625 | 33660 | 32821 | 每次循环10000000次 |
字符串 | 33739 | 33835 | 33617 | 每次循环10000000次 |
THREE.Vector3 | 42423 | 42281 | 15624 | 每次循环1000000次 |
THREE.Spherical | 35679 | 36249 | 15971 | 每次循环1000000次 |
结论
- 对于全部数据类型,情况2与情况1相比,代价一致,不会有性能的提升
- 对于JS基本类型,三种情况代价一致,chrome应该对其进行了优化,因此建议将JS基本类型变量声明放到循环体内部,程序更加易读
- 对于自定义类型,情况3与前两种情况相比,代价不到一半,性能有明显提升,因此建议将自定义类型声明及初始化放到循环体外部
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试for循环中的变量声明不同代价</title>
</head>
<body>
<h1>测试for循环中变量声明处于不同位置时的相应代价</h1>
<script src="../static/lib/three.js/r85/three.js"></script>
</body>
</html>
<script>
// 循环次数
var n = 1000000
// 获取时间戳
function get_time_stamp() {
return (new Date()).valueOf();
}
// 1. 变量声明在循环体内部
function test1() {
var result1 = []
var ts1_start = get_time_stamp()
for (var i = 0; i < n; i++) {
var t1 = new THREE.Spherical();
t1.set(i, Math.PI, Math.PI)
result1.push(t1)
}
var ts1_end = get_time_stamp()
var ts1 = ts1_end - ts1_start
console.log(ts1)
return ts1
}
// 2. 变量声明在循环体外部,但未初始化
function test2() {
var result2 = []
var ts2_start = get_time_stamp()
var t2
for (var i = 0; i < n; i++) {
t2 = new THREE.Spherical();
t2.set(i, Math.PI, Math.PI)
result2.push(t2)
}
var ts2_end = get_time_stamp()
var ts2 = ts2_end - ts2_start
console.log(ts2)
return ts2
}
// 3. 变量声明在循环体外部,并初始化
function test3() {
var result3 = []
var ts3_start = get_time_stamp()
var t3 = new THREE.Spherical();
for (var i = 0; i < n; i++) {
t3.set(i, Math.PI, Math.PI)
result3.push(t3)
}
var ts3_end = get_time_stamp()
var ts3 = ts3_end - ts3_start
console.log(ts3)
return ts3
}
// 测试100次,取总时间
var total = 0
for (var i = 0; i < 100; i++) {
var t = test3()
total += t
}
console.log("累计用时", total)
</script>