0、在javascript加载解析完之前后续的html不会加载。因此避免出现用户看到的页面延迟的情况,js代码和js引用写在body的底部。
1、由于每个script下载时会阻塞html加载过程,所以尽量减少script的标签,也尽量减少js文件数目的引用。总的来说,加载四个25KB的js比加载一个100KB的js来得慢。
2、如果js不影响dom结构的话,可以使用defer关键词延迟执行。
js的数据存储
js中的数据访问位置
直接量:仅代表本身,不代表存储位置。包括字符串,数字,数组,对象,函数,正则表达式等。他代表的是值的本身。
变量:var创建的存储数值的地方。
数组项:存放数组
对象成员:存放对象。
直接量和变量的访问性能消耗不大,但是数组项和对象成员访问性能消耗稍微大一点。
数组项指的是数组的成员,直接量中的数组是数组本身
对象成员指的是对象的方法或者属性的访问,不是对象本身。
基于原型
javascript是面向对象的,javascript的对象是基于原型的(相当有java的基于Object),原型定义了创建一个新对象所必须有的成员。任何一个对象都包含两部分,实例成员和原型成员。
当调用原型成员时,原型成员所在的深度越深,索引到的时间越长。(在一些优化的浏览器中不是特别明显)
如果使用了嵌套访问,如window.location.href,每一个.就多一次解析和索引,嵌套越深访问越慢,如果调用的属性不是实例成员,花费的时间更长。
所以每次调用对象成员都需要索引和解析,相比而言直接调用变量会快的多。因此在同一个函数中没有必要读取两次一个对象成员的值,而是应该用局部变量保存下来。
全局变量也会有类似的索引消耗。在一个方法执行时,会生成一个上下文,上下文作用域中存放所有成员,全局变量也在上下文作用域中,但是他的位置一般是作用域的底端,所以调用全局变量时要慢一些。常用的全局变量是document和window,多余一次调用的时候都可以用局部变量保存引用。
对象成员或嵌套对象成员或者全局变量,超过一次调用都应该用局部变量保存。数组项,集合项多次调用的也应该用变量保存。
DOM优化
浏览器对dom的解析和对js的解析在不同的文件中,对js的解析在文件jscript.dll,对dom的解析在mshtml.dll
“这对性能意味着什么呢?简单说来,两个独立的部分以功能接口连接就会带来性能损耗。一个很形象的比喻是把DOM看成一个岛屿,把JavaScript(ECMAScript)看成另一个岛屿,两者之间以一座收费桥连接。每次ECMAScript需要访问DOM时,你需要过桥,交一次“过桥费”。你操作DOM次数越多,费用就越高。一般的建议是尽量减少过桥次数,努力停留在ECMAScript岛上。本章将对此问题给出详细解答,告诉你应该关注什么地方,以提高用户交互速度”
如果是修改的费用更高。
修改DOM的方法有两种,innerHTML和createElement(),二者性能差别不大,有时候innerHTML更好,因为他可以先拼接字符串再一次性写入,最新的浏览器版本createEle更快,实际编码看开发爱好和用户爱好。
如下的循环会很慢
for(int i = 0; i<document.forms.length; i++){}
大小比较在每单次循环后都要执行,一方面他是嵌套调用,另一方面他是全局对象,最后每次为了获取长度都要重新去索引整个文档。应该将长度保存下来。
为了验证js每次都要查询长度,可以在方法体内新增一段代码,代码的内容是新增一个form,这样的话这个循环会是死循环,因为每次form都新增,length在变化,i<length永远成立。
document.forms是一个动态的集合,而不是一个数组。如果只是将集合保存到变量,每次比较大小使用变量的length的话,效率仍然会慢,实际保存的应该是length这个变量。
如果需要访问这个集合的内部属性,将他转换为一个数组去访问更快。但是转换的本身过程需要一定时间。toArray()是一个通用的集合转数组的方法。
浏览器提供了一个querySelectorAll()方法,查找CSS时候会快很多。函数返回的是类数组对象不是集合对象。
查询class=warn和notice的div:document.querySeletorAll('div.warning,div.notice');
修改DOM会引起重绘版,性能代价高,尽量再一次中修改完成。也可以在修改前先hide元素,修改完毕后在显示。
事件托管
当页面存在大量元素且都有一个或多个事件句柄(事件句柄是指事件发生时要进行的操作。如onclick是事件,submit()是句柄)和他关联的话,可能会影响性能。浏览器需要记录下所有的句柄。而很多句柄不会被调用。
事件托管是通过绑定多个元素的父元素,传入e,在事件中获取操作对象并进行操作。可以最小化句柄的数量。
细节
循环量大的时候可以通过递减,与0比较加快一点速度,for(int i = length;i--;){}
ifelse中将最常用的判断放最前面,当条件多时switch比if else要快,当判断的结果多且是数值的时候可以使用键值对存储,这样查询比前两者快得多。
用迭代代替递归,将计算过的值缓存下来,之后在遇到不要二次计算直接取缓存的数值。
字符串和正则表达式
var str = str + "one" + "two";优于 var str += "one"+"two";
后者需要新建一个临时字符串存放onetwo,然后连接str的值,然后赋值给str。前者只需要追加。大多数浏览器已经对字符串的连接做了优化。
网友评论