高性能JavaScript摘要

动态脚本元素

通过Dom方法建立script元素,在文件进行启动下载时,不会阻塞页面其它进程。

function loadScript(url, callback){
    var script = document.createElement('script');
	script.type = 'text/javascript';
	if (script.readyState){  //IE
	    script.onreadystatechange = function(){
		    if(script.readyState == 'loaded' || script.readyState = 'complete'){
			    script.onreadystatechange = null;
				callback();
			}
		}
	} else{
	    script.onload = function(){
		    callback();
		};
	}
	script.src = url;
	document.getElementsByTagName('head')[0].appendChild(script);
}

注意的是在加载多个JS文件时,加载顺序不是所有浏览器按照指定的顺序执行。

loadScript(url, function(){
    loadScript('file2',function(){
	    loadScript('file3.js',function(){
            alert('complete');
        });
	});
});

管理浏览器的JS代码

1、在<body>标签闭合之前,将所有的<script>标签放到页面底部。

2、合并脚本,减少<script>标签个数。

3、使用无阻塞下载JS脚本方法。

(1)、使用<script>.标签的defer属性。

(2)、动态创建<script>元素,下载JS代码。

(3)、使用XHR对象下载JS代码注入页面。

数据访问

1、访问直接量和局部变量的速度最快,相反,访问数组元素和对象成员相对较慢。

2、由于局部变量存在于作用域链的起始位置,因此访问局部变量比访问跨作用域变量更快。变量在作用域链中的位置越深,访问所需时间就越长。由于全局变量总处在作用域链的最末端,因此访问速度也是最慢的。

3、避免使用with语句,因为它会改变运行期上下文作用域链。同样,try-catch语句中的catch子语句也有同样的影响,因此也要小心使用。

4、嵌套的对象成员会明显影响性能,尽量少用。

5、属性活方法在原型链中的位置越深,访问他的速度也越慢。

6、通常来说,你可以通过把常用的对象成员、数组元素、跨域变量保存在局部变量中来改善JavaScript性能,因为局部变量访问速度更快。

DOM编程

操作DOM元素需要在JS的ECMA与DOM之间浪费时间,则要尽量减少DOM编程带来的性能损失。

1、最小化DOM访问次数,尽可能在JS端处理。

2、需要访问多次某个DOM节点,使用局部变量存储它的引用。

3、小心处理HTML的集合,因为他实时联系着底层文档。把集合的长度缓存到一个变量中,并在迭代中使用它。如果经常操作集合,建议把它拷贝到一个数组中。

4、如果可能的话,尽量使用速度更快的API,比如querySelectAll()和firstElementChild。

5、要留意重绘和重排;批量修改样式时,“离线”操作DOM树,使用缓存,并减少访问布局信息的次数。

6、动画中使用绝对定位,使用拖放代理。

7、使用事件委托减少事件处理器的数量。

innerHTML与DOM方法:如果在对性能有苛刻要求更新一大段的HTML,推荐使用innerHTML。在旧版本浏览器中innerHTML方法更快,在基于Webkit内核却相反。

克隆已有节点,更新页面内容只能稍快一点。

访问一个数组集合明显快于遍历一个HTML集合,但是如果把HTML集合拷贝到数组集合,会多遍历一次元素,因此是在特定的环境下起作用。

遍历DOM元素,可以通过nextSibling和childNodes两种方式,在IE中,nextSibling速度更快。

当页面布局和集合属性改变时,则会重排,读取属性则会等到重新渲染结束时,不需要在布局信息改变是查询它,并且要减少重绘和重排的次数。

批量修改DOM元素:

使元素脱离文档流,对其应用多重改变,最后把元素带回文档。

使DOM脱离文档的方法:

1、隐藏元素,应用修改,重新显示。

var ul = document.getElementById('mylist');
ul.style.display = 'none';
appendDataToElement(ul, data);
ul.style.display = 'block';

2、使用文档片断(document fragment)

var fragment = document.createDocumentFragment();
appendDataToElement(fragment, data);
document.getElementById('mylist').appendChild(fragment);

3、将元素拷贝到一个脱离文档的节点中,修改副本,完成后再替换。

var old = document.getElementById('mylist');
var clone = old.cloneNode(true);
appendDataToElement(clone, data);
old.parendNode.replace(clone, old);

使用绝对位置来定位页面的动画元素。

算法和流程控制

JS可用资源有限,写法和算法来控制优化更为重要。

1、for、while和do-while循环性能特性相似,所以没有一种循环类型明显快于或鳗鱼其他类型。

2、避免使用for-in循环,除非你需要遍历一个属性数量未知的对象。

3、改善循环性能的最佳方式是减少每次迭代的运算量和减少循环迭代次数。

4、switch总是比if-else快,但并不总是最佳解决方案。

5、在判断条件较多时,使用查找表比if-else和switch更快。

6、浏览器的调用栈大小限制了递归算法在JS中的应用,栈逸出错误会导致其他代码中断运行。

7、如果遇到栈溢出错误,可将方法改为迭代算法,或使用Memoization来避免重复的计算。

通过调到数组的顺序来提高循环性能。

达夫设备:

通过一次调用多次的循环内容,来实现迭代次数减少。

var i = items.length % 8;
var index = Math.floor(items.length / 8);
while (i){
    process(items[index * 8 + i - 1]);
	i --;
}

while (index){
     process(items[8 * index - 1]);
	 process(items[8 * index - 2]);
	 process(items[8 * index - 3]);
	 process(items[8 * index - 4]);
	 process(items[8 * index - 5]);
	 process(items[8 * index - 6]);
	 process(items[8 * index - 7]);
	 process(items[8 * index - 8]);
	 index --;
}

字符串和正则表达式

这一章多少有点点抽象,正则表达式的学问还是蛮深的。

1、当连接数量巨大或尺寸巨大的字符串时,数组项连接是唯一在IE7及更早版本中性能合理的方法。

2、如果不考虑IE及更早版本的性能,数组项连接是最慢的字符串连接方法之一。推荐使用简单的+和+=操作符替代,避免不必要的中间字符串。

3、回溯即使正则表达式匹配成功功能的基本组成部分,也是正则表达式的低效之源。

4、回溯失控发生在正则表达式应该快速匹配的地方,但因为某些特殊的字符串匹配动作导致运行缓慢甚至浏览器崩溃。避免这个问题的方法是:使相邻的资源互斥,避免嵌套词对同一字符串的相同部分多次匹配,通过重复利用向前查看的原子组取出不必要的回溯。

5、提高正则表达式的各种技术手段会有助于正则表达式更快地匹配,并在非匹配位置花上更少的时间。

a、关注如何让匹配更快失败。

b、正则表达式以简单、必须的字元开始。

c、使用量词模式,使他们后面的字元互斥。

d、减少分支数量,减小分支范围。

e、使用非捕获组。

f、之捕获感兴趣的文本以减少后处理。

g、暴露必须的字元。

h、使用合适的量词。

i、把正则表达式复制给变量并重用他们。

j、将复杂的正则表达式拆分为简单的片段。

6、正则表达式并不总是完成工作的最佳工具,尤其是当你之搜索字面字符串的时候。

7、尽管有很多方法可以去除掉字符串的首尾空格,但使用两个简单的正则表达式(一个用于去除头部空白,另一个用来去除掉尾部空白)来处理大量字符串内容能提供一个简洁而跨浏览器的方法。从字符串末尾开始循环向前搜索第一个非空白字符,或者将此技术同正则表达式结合起来,会提供一个更好的替代方案,它很少受到字符串的长度的影响。

String.prototype.trim = function(){
   return this.replace(/^\s+/,  '').replace(/\s+$/, '');
};

String.prototype.trim = function(){
    var str = this.replace(/^\s+/, ''),
	    end = str.length - 1,
		ws = /\s/;
	while (ws.test(str.charAt(end))){
	    end --;
	}
	return str.slice(0, end + 1);
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值