<高性能JavaScript>笔记 [4~6]


四:算法和流程控制

- for, whiledo-while 循环性能特性相似,所以没有一种循环类型明显快于或慢于其他类型.
- 避免使用 for-in 循环,除非你需要遍历一个属性数量未知的对象.(因为会对原型链进行循环,产生不必要的性能损耗)
- 改善循环性能的最佳方式是减少每次迭代的运算量和减少循环迭代次数.
- 通常来说, switch 总是比 if-else 快,但并不总是最佳的解决方案.
- 在判断条件较多,且键和值之间存在逻辑映射时,使用查找表笔 switchif-else 更快.而当键和值是离散的情况下, switchif-else 更适用.
- 浏览器的调用栈大小限制了递归算法在JavaScript中的应用;栈溢出错误会导致其他代码中断运行.
- 如果你遇到栈溢出的错误,可将方法改为迭代算法,或使用Memoization来避免重复计算.(Memoization是一种性能优化的技术,通过缓存数据的方式避免重复性的操作)

使用循环体遍历数组时,记得先把数组的长度存放在局部变量中,多次操作的性能损耗.
还可以通过颠倒数组的顺序来提高循环性能.
for (var i = array.length; i--; ) {
//循环体
}
这样可以把循环的每次必要操作减少为:
 + 控制条件中的比较 ( i == true )
 + 减法操作 ( i-- )
避免了 for 循环中判断数值大小的操作.

关于条件语句 if-elseswitch 性能上的差别.
大多数情况下 switchif-else 运行得要快,但只有当判断的条件数量很大时才有比较明显的差距.
这主要是因为大多数语言对 switch 语句的实现都采用了 branch table(分支表) 索引来实现优化.
而JavaScript还有一个特别的地方,因为使用 switch 时,所有的判断都通过全等操作符(===).这样就避免了类型转换的损耗.因为大家都习惯了直接用等号(==)来判断,但在JavaScript中这是有差别的,在判断前会先进行类型的转换.
所以: 
123 == "123"; //true




五:字符串和正则表达式

- 当链接数量巨大或尺寸巨大的字符串时, 数组项链接是唯一在 IE7 及更早版本中性能合理的方法.
- 如果不需要考虑 IE7 及更早版本的性能, 数组项链接是最慢的字符串链接方法之一.推荐使用简单的+和+=操作符替代,避免不必要的中间字符串.
- 回溯既是正则表达式匹配功能的基本组成部分, 也是正则表达式的低效之源.
- 回溯失控发生在正则表达式本应快速匹配的地方, 但因为某些特殊的字符串匹配动作导致运行缓慢甚至浏览器崩溃. 避免这个问题的方法是: 使相邻的字元互斥, 避免嵌套量词对同一字符串的相同部分多次匹配, 通过复制利用向前查看的原子组去除不必要的回溯.
- 提高正则表达式效率的各种技术手段会有助于正则表达式更快地匹配, 并在非匹配位置上花更少的时间.
- 正则表达式并不总是完成工作的最佳工具, 尤其当你只搜索字面字符串的时候.
- 尽管有许多方法去除字符串的首尾空白, 但是用两个简单的正则表达式(一个处理头部空白, 另一个处理尾部空白)来处理大量字符串内容能提供一个简洁而跨浏览器的方法. 从字符串末尾开始循环向前搜索第一个非空白字符, 或者将此技术同正则表达式结合起来, 会提供一个更好的解决方法, 它很少受到字符串长度影响.

除IE外,其他浏览器会出现以下情况:
str = str + "one";  //意味着拷贝字符串"one"并附加在str后.
str = "one" + str;  //则意味着拷贝str字符串附加到"one"之后.
如果str很大, 则拷贝过程占用内存的情况会很严重.

另外,
str = str + "one" + "two" 
比 
str += "one" + "two" 
更优.
因为后者会生成一个临时的字符串来存放"onetwo", 而后者直接把后面的字符串附加在str上.

关于正则表达式的部分, 因为没有进行过系统的学习, 看起来有点混乱, 理解得也不是很好.
后来网上查看了一下,很多人批评正则这部分翻译得很差。





六:快速响应的用户界面

共用于执行JavaScript和更新用户界面的进程通常被称为 The Browser UI Thread (浏览器UI线程)

因为浏览器UI线程是一个简单的列队系统,如果某个工作任务占用时间过长,会导致页面出现“假死”的状态。
所以不同的浏览器根据这种情况,都有各自的处理方式,一般分为两种:调用栈大小限制长时间运行脚本限制
+ IE从第四版开始,默认限制500万条语句。
+ Firefox默认限制为10秒。
+ Safari默认限制为5秒。
+ Chrome没有单独的长运行脚本限制,替代做法是依赖其通用崩溃监测系统来处理此类问题。
+ Opera没有长运行脚本限制,它会执行代码直到结束。

应该避免长时间运行的脚本。单个JavaScript操作花费的总时间不应该超过100毫秒
因为如果界面在100毫秒内响应用户输入,用户会认为自己在“直接操纵界面中的对象”。
假如超过100毫秒,则意味着用户会感到自己与界面失去了联系。

其实整一章书都在围绕着如何把单个JavaScript操作控制在100毫秒之内,而定时器处理(setTimeout 和 setInterval)就是一个很好的办法。

function timedProcessArray(tiems, process, callback) {
	var todo = items.concat(); //克隆原数组
	setTimeout(function() {
		var start = +newDate(); //记录开始时间
		do {
			process(todo.shift());
		} while (todo.length > 0 && (+new Date() - start < 50));  //执行时间大于50毫秒中断

		if(todo.length > 0) {
			setTimeout(arguments.callee, 25);
		} else {
			callback(items); 
		}
	}, 25);
}
以上就是一个定时器处理数组的方法,通过控制每次操作数组的时间在50毫秒内,然后“暂停”25毫秒,让UI有时间刷新,再继续操作数组。

至于,为什么要设置间隔为25毫秒呢?
这是因为考虑不同浏览器和操作系统之间的差异,这个值是有个通用的有效值。延迟的最小值建议为25毫秒。
而把每次对数组的执行时间控制在50毫秒,是本书作者的意思。不过还是建议尽量不要将数值设置得太接近100毫秒,因为不同浏览器之间有差异,应尽量保持用户体验的一致性。

最后还介绍了Web workers这个新特性,不过目前支持的浏览器有限,就不在此介绍了。






原文地址:https://www.cnblogs.com/maplejan/p/2731995.html