高性能JavaScript(4)

JavaScript和其他编程语言一样,写法和算法会影响运行时间,代码数量少并不代表运行速度就快,代码数量多也不一定会影响运行速度。代码的整体结构才是影响运行速度的主要因素之一。

循环

在大多数编程语言中,循环被认为是最费时间的,因此也是改善性能的关键点之一。

JavaScript中的几种循环类型:

  • for循环
  • while循环
  • do-while循环
  • for-in循环

这些循环类型中,for-in的效率明显最低,因为每次迭代都会搜索实例或原型属性,产生了更多开销。因此,对于一个未知属性数量的对象进行迭代可以采用for-in,但是其他情况下应该尽量避免,采用其他类型。

1
2
3
4
5
var props = ['name', 'address'], i = 0
while (i < props.length) {
process(obj[props[i++]])
}

优化

1
2
3
4
// 原始循环
for (var i = 0; i < items.length; i++) {
process(items[i])
}

根据之前说过的作用域查找规则,局部变量远比属性查找快的多,将length的属性值存储到局部变量,一次循环只访问了一次属性,从而提高运行速度。

1
2
3
4
// 优化属性查找
for (var i = 0, len = items.length; i < len; i++) {
process(items[i])
}

通常情况下,数组的查找顺序和执行任务无关,因此可以采用倒序的方式提高新能。

1
2
3
4
// 优化属性查找并倒序
for (var i = items.length; i--;) {
process(items[i])
}

相比减少属性访问,将减法操作合并到了控制条件中,控制条件已经从两次比较(迭代次数是否小于总数?是否为true?)变为一次比较(是否为true?),从而进一步提高运行速度。

条件语句

JavaScript中的控制语句类型:

  • if-else
  • switch

一般情况下,会从代码易读性来做取舍。根据条件数量来判断:条件数量越大,使用switch,否则使用if-else。

优化

if-else

if-else中的条件语句顺序应该按照从最大概率到最小概率的顺序排列,最可能出现的应该放在首位,达到优化速度的目的。

另一种优化则是将多个判断语句变成嵌套的if-else语句,实际是利用了二分法,分为不同区间,然后逐步缩小范围。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 原始
if (value === 0) {
return result0
} else if (value === 1) {
return result1
} else if (value === 2) {
return result2
} else if (value === 3) {
return result3
} else if (value === 4) {
return result4
} else if (value === 5) {
return result5
} else if (value === 6) {
return result6
} else {
return result7
}
// 优化后
if (value < 4) {
if (value < 2) {
if (value === 0) {
return result0
} else {
return result1
}
} else {
if (value === 2) {
return result2
} else {
return result3
}
}
} else {
if (value < 6) {
if (value === 4) {
return result4
} else {
return result5
}
} else {
if (value === 6) {
return result6
} else {
return result7
}
}
}

查找表

当单个键和单个值之间存在逻辑关系,就像上文提到的例子,我们可以通过查找表,用一个数组作为查找表,代替条件语句,提高运行速度。

1
2
3
var results = [ result0, result1, result2, result3, result4, result5, result6, result7]
return results[value]