高性能JavaScript
1. 加载与执行
- 脚本尽可能放在body标签的最底部
知乎上关于这个问题igetit的回答还是很棒的。
- 减少脚本数量(合并)
在页面加载完成之后再加载脚本
- 使用defer属性
使用js动态加载
var script = document.createElement("script"); script.type = "text/javascript" script.src = "xxx.js" document.getElementByTagName("head")[0].appendChild(script)
文末使用
loadScript("xxx.js", function(){ Application.init(); });
或使用lasyload类库(同loadscript)
2. 数据访问
使用局部变量
使用多次的全局变量缓存到局部变量中
var doc = document
try-catch 只用来捕获已知的可能会发生的错误
- with语句用来给对象的所有属性创建一个变量,会影响性能不推荐使用
- 只用确实有必要的时候才推荐使用动态作用域
- 访问对象成员速度比直接访问变量或者直接量要慢
对象成员嵌套越深访问速度越慢
window.location.href 比 location.href 要慢 遇到点操作符就会去遍历对象成员
缓存对象成员值
3. DOM编程
- 减少访问DOM的次数, 尽量留在js这边处理
- innerHTML和document.createElement()的原生DOM方法效率相差不大
集合较慢
可以使用
var coll = document.getElementByTagName('div'); var arr = toArray(coll); for(var count = 0; count < arr.length;Count++){...}
访问集合元素时使用局部变量
el = coll[count] name = el.nodeName type = el.nodeType
最小化重绘和重排
合并改变一次处理
var el = documeng.getElementById('mydiv'); el.style.borderLeft = "1px"; el.style.borderLeft = "1px";
换为
var el = document.getElementById('mydiv'); el.style.cssText = 'border-left:1px;border-right:1px'
也可以定义两个属性,更改的时候直接更改类名
批量修改DOM
三步走:
1. 使元素脱离文档流 2. 对其应用多重改变 3. 把元素带回文档流
三个方法:
1. 隐藏元素,应用修改,重新显示 2. 使用文档片段在当前DOM之外构建一个子树,再把它拷贝回文档 3. 将原修始元素复制到一个脱离文档流的节点中,修改副本,在替换原来的元素
缓存布局信息,使用临时变量记录布局位置信息
让元素脱离动画流
三步:
1. 绝对定位页面上的动画元素脱离文档流 2. 让元素动起来(这只是小区域的重绘) 3. 动画结束,恢复定位
使用事件委托减少事件处理接收器
4. 算法和流程控制
- for-in循环最慢(尽量避免使用)
- 减少迭代工作量
item.length => len = item.length
- 基于函数的迭代量会慢一些
- 从易读性和效率两方面考虑都是数量少的时候用if-else,数量多的时候使用switch
查找表是一个不错的选择
var results = ['12','13','14'...] return results[value]
5. 使用正则表达式
+和+=
str += "one" + "two"; 慢 str += "one" str += "two" 快 str = str + "one" + "two" 快 str = ['one', 'two'].join("") 很快 str = str.concat ('one') str = str.concat('two') 很慢
+= 会产生缓存对象
正则表达式优化
贪婪量词 *
懒惰量词 *?
去除字符串首位的空白
if(!String.prototype.trim){ String.prototype.trim = function(){ return this.replace(/^\S+/, "").replace(/\S+$/, "") // 或 // return this.replace(/^\S+/, "").replace(\s\S*$/, "") } } var str = "\t\n abc ".trim(); 当然自带的trim是经过特殊优化的,是最快的
6. 快速响应的用户界面
- JavaScript运行时间最好不要超过100ms
- setTimeout() setInterval()
使用定时器处理数组
var todo = item.concat(); setTimeout(function(){ process(todo.shift(1)); if(todo.length > 0){ SetTimeout(arguments.callee, 25) }else{ callback(item); } }); //todo.shift(1) 返回它的第一条引用,并从数组中删除 // 相同的参数,所以用arguments.callee //不需要再处理则调用callback函数
7. Ajax
- XHR、动态脚本注入和multipart XHR这三种比较常用
- JSON 可以用eval(…)直接转换后处理,但是这样做存在安全风险
自定义格式
1:ali:Alice:alice@alice.com
使用JS split()处理数组
8. 编程实践
使用Object/Array直接量
var myObj = new Object(); myObj.name = "Nick"; myObj.count = 50; .... => var myObj = { name : "nick", count : 5 ... } var myArr = new Array(); myArr[0] = 'nick'; myArr[1] = 50; => var myArr = ["nick", 50]
不要做重复的工作
使用速度快的部分
位操作代替数学操作符
使用原生的Math方法取代数学运算
9. 构建并部署
- 合并多个JavaScript文件
- 预处理JavaScript文件
需要配置Apache
- JavaScript压缩(可以使用JSMin)
- http压缩 gzip
- 缓存JavaScript文件,使用Expire HTTP响应头
- 使用版本问题结局缓存永不过期问题
- 使用内容分发网络(CDN)